Préparation feature 2.0
This commit is contained in:
2
MareAPI
2
MareAPI
Submodule MareAPI updated: 3b175900c1...deb911cb0a
@@ -263,6 +263,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
IsTemporary = group.IsTemporary,
|
IsTemporary = group.IsTemporary,
|
||||||
ExpiresAt = group.ExpiresAt,
|
ExpiresAt = group.ExpiresAt,
|
||||||
|
AutoDetectVisible = group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = group.PasswordTemporarilyDisabled,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
IsTemporary = group.IsTemporary,
|
IsTemporary = group.IsTemporary,
|
||||||
ExpiresAt = group.ExpiresAt,
|
ExpiresAt = group.ExpiresAt,
|
||||||
|
AutoDetectVisible = group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = group.PasswordTemporarilyDisabled,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +276,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
IsTemporary = newGroup.IsTemporary,
|
IsTemporary = newGroup.IsTemporary,
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
ExpiresAt = newGroup.ExpiresAt,
|
||||||
|
AutoDetectVisible = newGroup.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = newGroup.PasswordTemporarilyDisabled,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid));
|
_logger.LogCallInfo(MareHubLogger.Args(gid));
|
||||||
@@ -353,6 +357,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
IsTemporary = newGroup.IsTemporary,
|
IsTemporary = newGroup.IsTemporary,
|
||||||
ExpiresAt = newGroup.ExpiresAt,
|
ExpiresAt = newGroup.ExpiresAt,
|
||||||
|
AutoDetectVisible = newGroup.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = newGroup.PasswordTemporarilyDisabled,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(gid, "Temporary", expiresAtUtc));
|
_logger.LogCallInfo(MareHubLogger.Args(gid, "Temporary", expiresAtUtc));
|
||||||
@@ -449,22 +455,130 @@ public partial class MareHub
|
|||||||
_logger.LogCallInfo(MareHubLogger.Args(dto.Group));
|
_logger.LogCallInfo(MareHubLogger.Args(dto.Group));
|
||||||
|
|
||||||
var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid).ConfigureAwait(false);
|
var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == aliasOrGid || g.Alias == aliasOrGid).ConfigureAwait(false);
|
||||||
var groupGid = group?.GID ?? string.Empty;
|
|
||||||
var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
|
||||||
var hashedPw = StringUtils.Sha256String(dto.Password);
|
var hashedPw = StringUtils.Sha256String(dto.Password);
|
||||||
|
|
||||||
|
return await JoinGroupInternal(group, aliasOrGid, hashedPw, allowPasswordless: false, skipInviteCheck: false).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<bool> SyncshellDiscoveryJoin(GroupDto dto)
|
||||||
|
{
|
||||||
|
var gid = dto.Group.GID.Trim();
|
||||||
|
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(dto.Group));
|
||||||
|
|
||||||
|
var group = await DbContext.Groups.Include(g => g.Owner).AsNoTracking().SingleOrDefaultAsync(g => g.GID == gid).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return await JoinGroupInternal(group, gid, hashedPassword: null, allowPasswordless: true, skipInviteCheck: true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<List<SyncshellDiscoveryEntryDto>> SyncshellDiscoveryList()
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
|
var groups = await DbContext.Groups.AsNoTracking()
|
||||||
|
.Include(g => g.Owner)
|
||||||
|
.Where(g => g.AutoDetectVisible && (!g.IsTemporary || g.ExpiresAt == null || g.ExpiresAt > DateTime.UtcNow))
|
||||||
|
.ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var groupIds = groups.Select(g => g.GID).ToArray();
|
||||||
|
var memberCounts = await DbContext.GroupPairs.AsNoTracking()
|
||||||
|
.Where(p => groupIds.Contains(p.GroupGID))
|
||||||
|
.GroupBy(p => p.GroupGID)
|
||||||
|
.Select(g => new { g.Key, Count = g.Count() })
|
||||||
|
.ToDictionaryAsync(k => k.Key, k => k.Count, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return groups.Select(g => new SyncshellDiscoveryEntryDto
|
||||||
|
{
|
||||||
|
GID = g.GID,
|
||||||
|
Alias = g.Alias,
|
||||||
|
OwnerUID = g.OwnerUID,
|
||||||
|
OwnerAlias = g.Owner.Alias,
|
||||||
|
MemberCount = memberCounts.TryGetValue(g.GID, out var count) ? count : 0,
|
||||||
|
AutoAcceptPairs = g.InvitesEnabled,
|
||||||
|
Description = null,
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<SyncshellDiscoveryStateDto?> SyncshellDiscoveryGetState(GroupDto dto)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(dto.Group));
|
||||||
|
|
||||||
|
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.Group.GID).ConfigureAwait(false);
|
||||||
|
if (!hasRights) return null;
|
||||||
|
|
||||||
|
return new SyncshellDiscoveryStateDto
|
||||||
|
{
|
||||||
|
GID = group.GID,
|
||||||
|
AutoDetectVisible = group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = group.PasswordTemporarilyDisabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<bool> SyncshellDiscoverySetVisibility(SyncshellDiscoveryVisibilityRequestDto dto)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(dto));
|
||||||
|
|
||||||
|
var (hasRights, group) = await TryValidateGroupModeratorOrOwner(dto.GID).ConfigureAwait(false);
|
||||||
|
if (!hasRights) return false;
|
||||||
|
|
||||||
|
group.AutoDetectVisible = dto.AutoDetectVisible;
|
||||||
|
group.PasswordTemporarilyDisabled = dto.AutoDetectVisible;
|
||||||
|
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
await DbContext.Entry(group).Reference(g => g.Owner).LoadAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var groupPairs = await DbContext.GroupPairs.AsNoTracking().Where(p => p.GroupGID == group.GID).Select(p => p.GroupUserUID).ToListAsync().ConfigureAwait(false);
|
||||||
|
await Clients.Users(groupPairs).Client_GroupSendInfo(new GroupInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.GetGroupPermissions())
|
||||||
|
{
|
||||||
|
IsTemporary = group.IsTemporary,
|
||||||
|
ExpiresAt = group.ExpiresAt,
|
||||||
|
AutoDetectVisible = group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = group.PasswordTemporarilyDisabled,
|
||||||
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> JoinGroupInternal(Group? group, string aliasOrGid, string? hashedPassword, bool allowPasswordless, bool skipInviteCheck)
|
||||||
|
{
|
||||||
|
if (group == null) return false;
|
||||||
|
|
||||||
|
var groupGid = group.GID;
|
||||||
|
var existingPair = await DbContext.GroupPairs.AsNoTracking().SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid).ConfigureAwait(false);
|
var existingUserCount = await DbContext.GroupPairs.AsNoTracking().CountAsync(g => g.GroupGID == groupGid).ConfigureAwait(false);
|
||||||
var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false);
|
var joinedGroups = await DbContext.GroupPairs.CountAsync(g => g.GroupUserUID == UserUID).ConfigureAwait(false);
|
||||||
var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID).ConfigureAwait(false);
|
var isBanned = await DbContext.GroupBans.AnyAsync(g => g.GroupGID == groupGid && g.BannedUserUID == UserUID).ConfigureAwait(false);
|
||||||
var oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPw).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (group == null
|
GroupTempInvite? oneTimeInvite = null;
|
||||||
|| (!string.Equals(group.HashedPassword, hashedPw, StringComparison.Ordinal) && oneTimeInvite == null)
|
if (!string.IsNullOrEmpty(hashedPassword))
|
||||||
|
{
|
||||||
|
oneTimeInvite = await DbContext.GroupTempInvites.SingleOrDefaultAsync(g => g.GroupGID == groupGid && g.Invite == hashedPassword).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowPasswordless && !group.AutoDetectVisible)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool passwordBypass = group.PasswordTemporarilyDisabled || allowPasswordless;
|
||||||
|
bool passwordMatches = !string.IsNullOrEmpty(hashedPassword) && string.Equals(group.HashedPassword, hashedPassword, StringComparison.Ordinal);
|
||||||
|
bool hasValidCredential = passwordBypass || passwordMatches || oneTimeInvite != null;
|
||||||
|
|
||||||
|
if (!hasValidCredential
|
||||||
|| existingPair != null
|
|| existingPair != null
|
||||||
|| existingUserCount >= _maxGroupUserCount
|
|| existingUserCount >= _maxGroupUserCount
|
||||||
|| !group.InvitesEnabled
|
|| (!skipInviteCheck && !group.InvitesEnabled)
|
||||||
|| joinedGroups >= _maxJoinedGroupsByUser
|
|| joinedGroups >= _maxJoinedGroupsByUser
|
||||||
|| isBanned)
|
|| isBanned)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (oneTimeInvite != null)
|
if (oneTimeInvite != null)
|
||||||
{
|
{
|
||||||
@@ -486,13 +600,17 @@ public partial class MareHub
|
|||||||
|
|
||||||
_logger.LogCallInfo(MareHubLogger.Args(aliasOrGid, "Success"));
|
_logger.LogCallInfo(MareHubLogger.Args(aliasOrGid, "Success"));
|
||||||
|
|
||||||
await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(group.ToGroupData(), group.Owner.ToUserData(), group.GetGroupPermissions(), newPair.GetGroupPairPermissions(), newPair.GetGroupPairUserInfo())
|
var owner = group.Owner ?? await DbContext.Users.AsNoTracking().SingleAsync(u => u.UID == group.OwnerUID).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Clients.User(UserUID).Client_GroupSendFullInfo(new GroupFullInfoDto(group.ToGroupData(), owner.ToUserData(), group.GetGroupPermissions(), newPair.GetGroupPairPermissions(), newPair.GetGroupPairUserInfo())
|
||||||
{
|
{
|
||||||
IsTemporary = group.IsTemporary,
|
IsTemporary = group.IsTemporary,
|
||||||
ExpiresAt = group.ExpiresAt,
|
ExpiresAt = group.ExpiresAt,
|
||||||
|
AutoDetectVisible = group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = group.PasswordTemporarilyDisabled,
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
var self = DbContext.Users.Single(u => u.UID == UserUID);
|
var self = await DbContext.Users.SingleAsync(u => u.UID == UserUID).ConfigureAwait(false);
|
||||||
|
|
||||||
var groupPairs = await DbContext.GroupPairs.Include(p => p.GroupUser).Where(p => p.GroupGID == group.GID && p.GroupUserUID != UserUID).ToListAsync().ConfigureAwait(false);
|
var groupPairs = await DbContext.GroupPairs.Include(p => p.GroupUser).Where(p => p.GroupGID == group.GID && p.GroupUserUID != UserUID).ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
@@ -646,6 +764,8 @@ public partial class MareHub
|
|||||||
{
|
{
|
||||||
IsTemporary = g.Group.IsTemporary,
|
IsTemporary = g.Group.IsTemporary,
|
||||||
ExpiresAt = g.Group.ExpiresAt,
|
ExpiresAt = g.Group.ExpiresAt,
|
||||||
|
AutoDetectVisible = g.Group.AutoDetectVisible,
|
||||||
|
PasswordTemporarilyDisabled = g.Group.PasswordTemporarilyDisabled,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MareSynchronos.API.Dto.McdfShare;
|
||||||
|
using MareSynchronosServer.Utils;
|
||||||
|
using MareSynchronosShared.Models;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Hubs;
|
||||||
|
|
||||||
|
public partial class MareHub
|
||||||
|
{
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<List<McdfShareEntryDto>> McdfShareGetOwn()
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
|
var shares = await DbContext.McdfShares.AsNoTracking()
|
||||||
|
.Include(s => s.Owner)
|
||||||
|
.Include(s => s.AllowedIndividuals)
|
||||||
|
.Include(s => s.AllowedSyncshells)
|
||||||
|
.Where(s => s.OwnerUID == UserUID)
|
||||||
|
.OrderByDescending(s => s.CreatedUtc)
|
||||||
|
.ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
return shares.Select(s => MapShareEntryDto(s, true)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<List<McdfShareEntryDto>> McdfShareGetShared()
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo();
|
||||||
|
|
||||||
|
var userGroups = await DbContext.GroupPairs.AsNoTracking()
|
||||||
|
.Where(p => p.GroupUserUID == UserUID)
|
||||||
|
.Select(p => p.GroupGID.ToUpperInvariant())
|
||||||
|
.ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var shares = await DbContext.McdfShares.AsNoTracking()
|
||||||
|
.Include(s => s.Owner)
|
||||||
|
.Include(s => s.AllowedIndividuals)
|
||||||
|
.Include(s => s.AllowedSyncshells)
|
||||||
|
.Where(s => s.OwnerUID != UserUID)
|
||||||
|
.OrderByDescending(s => s.CreatedUtc)
|
||||||
|
.ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
var accessible = shares.Where(s => ShareAccessibleToUser(s, userGroups) && (!s.ExpiresAtUtc.HasValue || s.ExpiresAtUtc > now)).ToList();
|
||||||
|
|
||||||
|
return accessible.Select(s => MapShareEntryDto(s, false)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<bool> McdfShareUpload(McdfShareUploadRequestDto dto)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(dto.ShareId));
|
||||||
|
|
||||||
|
var normalizedUsers = dto.AllowedIndividuals
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(NormalizeUid)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
var normalizedGroups = dto.AllowedSyncshells
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(NormalizeGroup)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var share = await DbContext.McdfShares
|
||||||
|
.Include(s => s.AllowedIndividuals)
|
||||||
|
.Include(s => s.AllowedSyncshells)
|
||||||
|
.SingleOrDefaultAsync(s => s.Id == dto.ShareId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (share != null && !string.Equals(share.OwnerUID, UserUID, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
if (share == null)
|
||||||
|
{
|
||||||
|
share = new McdfShare
|
||||||
|
{
|
||||||
|
Id = dto.ShareId,
|
||||||
|
OwnerUID = UserUID,
|
||||||
|
CreatedUtc = now,
|
||||||
|
};
|
||||||
|
DbContext.McdfShares.Add(share);
|
||||||
|
}
|
||||||
|
|
||||||
|
share.Description = dto.Description ?? string.Empty;
|
||||||
|
share.CipherData = dto.CipherData ?? Array.Empty<byte>();
|
||||||
|
share.Nonce = dto.Nonce ?? Array.Empty<byte>();
|
||||||
|
share.Salt = dto.Salt ?? Array.Empty<byte>();
|
||||||
|
share.Tag = dto.Tag ?? Array.Empty<byte>();
|
||||||
|
share.ExpiresAtUtc = dto.ExpiresAtUtc;
|
||||||
|
share.UpdatedUtc = now;
|
||||||
|
|
||||||
|
share.AllowedIndividuals.Clear();
|
||||||
|
foreach (var uid in normalizedUsers)
|
||||||
|
{
|
||||||
|
share.AllowedIndividuals.Add(new McdfShareAllowedUser
|
||||||
|
{
|
||||||
|
ShareId = share.Id,
|
||||||
|
AllowedIndividualUid = uid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
share.AllowedSyncshells.Clear();
|
||||||
|
foreach (var gid in normalizedGroups)
|
||||||
|
{
|
||||||
|
share.AllowedSyncshells.Add(new McdfShareAllowedGroup
|
||||||
|
{
|
||||||
|
ShareId = share.Id,
|
||||||
|
AllowedGroupGid = gid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<McdfShareEntryDto?> McdfShareUpdate(McdfShareUpdateRequestDto dto)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(dto.ShareId));
|
||||||
|
|
||||||
|
var share = await DbContext.McdfShares
|
||||||
|
.Include(s => s.AllowedIndividuals)
|
||||||
|
.Include(s => s.AllowedSyncshells)
|
||||||
|
.Include(s => s.Owner)
|
||||||
|
.SingleOrDefaultAsync(s => s.Id == dto.ShareId && s.OwnerUID == UserUID)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (share == null) return null;
|
||||||
|
|
||||||
|
share.Description = dto.Description ?? string.Empty;
|
||||||
|
share.ExpiresAtUtc = dto.ExpiresAtUtc;
|
||||||
|
share.UpdatedUtc = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var normalizedUsers = dto.AllowedIndividuals
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(NormalizeUid)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
var normalizedGroups = dto.AllowedSyncshells
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(NormalizeGroup)
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
share.AllowedIndividuals.Clear();
|
||||||
|
foreach (var uid in normalizedUsers)
|
||||||
|
{
|
||||||
|
share.AllowedIndividuals.Add(new McdfShareAllowedUser
|
||||||
|
{
|
||||||
|
ShareId = share.Id,
|
||||||
|
AllowedIndividualUid = uid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
share.AllowedSyncshells.Clear();
|
||||||
|
foreach (var gid in normalizedGroups)
|
||||||
|
{
|
||||||
|
share.AllowedSyncshells.Add(new McdfShareAllowedGroup
|
||||||
|
{
|
||||||
|
ShareId = share.Id,
|
||||||
|
AllowedGroupGid = gid,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
return MapShareEntryDto(share, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<bool> McdfShareDelete(Guid shareId)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(shareId));
|
||||||
|
|
||||||
|
var share = await DbContext.McdfShares.SingleOrDefaultAsync(s => s.Id == shareId && s.OwnerUID == UserUID).ConfigureAwait(false);
|
||||||
|
if (share == null) return false;
|
||||||
|
|
||||||
|
DbContext.McdfShares.Remove(share);
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize(Policy = "Identified")]
|
||||||
|
public async Task<McdfSharePayloadDto?> McdfShareDownload(Guid shareId)
|
||||||
|
{
|
||||||
|
_logger.LogCallInfo(MareHubLogger.Args(shareId));
|
||||||
|
|
||||||
|
var share = await DbContext.McdfShares
|
||||||
|
.Include(s => s.AllowedIndividuals)
|
||||||
|
.Include(s => s.AllowedSyncshells)
|
||||||
|
.SingleOrDefaultAsync(s => s.Id == shareId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (share == null) return null;
|
||||||
|
|
||||||
|
var userGroups = await DbContext.GroupPairs.AsNoTracking()
|
||||||
|
.Where(p => p.GroupUserUID == UserUID)
|
||||||
|
.Select(p => p.GroupGID.ToUpperInvariant())
|
||||||
|
.ToListAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
bool isOwner = string.Equals(share.OwnerUID, UserUID, StringComparison.Ordinal);
|
||||||
|
if (!isOwner && (!ShareAccessibleToUser(share, userGroups) || (share.ExpiresAtUtc.HasValue && share.ExpiresAtUtc.Value <= DateTime.UtcNow)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
share.DownloadCount++;
|
||||||
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
return new McdfSharePayloadDto
|
||||||
|
{
|
||||||
|
ShareId = share.Id,
|
||||||
|
Description = share.Description,
|
||||||
|
CipherData = share.CipherData,
|
||||||
|
Nonce = share.Nonce,
|
||||||
|
Salt = share.Salt,
|
||||||
|
Tag = share.Tag,
|
||||||
|
CreatedUtc = share.CreatedUtc,
|
||||||
|
ExpiresAtUtc = share.ExpiresAtUtc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeUid(string candidate) => candidate.Trim().ToUpperInvariant();
|
||||||
|
private static string NormalizeGroup(string candidate) => candidate.Trim().ToUpperInvariant();
|
||||||
|
|
||||||
|
private static McdfShareEntryDto MapShareEntryDto(McdfShare share, bool isOwner)
|
||||||
|
{
|
||||||
|
return new McdfShareEntryDto
|
||||||
|
{
|
||||||
|
Id = share.Id,
|
||||||
|
Description = share.Description,
|
||||||
|
CreatedUtc = share.CreatedUtc,
|
||||||
|
UpdatedUtc = share.UpdatedUtc,
|
||||||
|
ExpiresAtUtc = share.ExpiresAtUtc,
|
||||||
|
DownloadCount = share.DownloadCount,
|
||||||
|
IsOwner = isOwner,
|
||||||
|
OwnerUid = share.OwnerUID,
|
||||||
|
OwnerAlias = share.Owner?.Alias ?? string.Empty,
|
||||||
|
AllowedIndividuals = share.AllowedIndividuals.Select(i => i.AllowedIndividualUid).OrderBy(s => s, StringComparer.OrdinalIgnoreCase).ToList(),
|
||||||
|
AllowedSyncshells = share.AllowedSyncshells.Select(g => g.AllowedGroupGid).OrderBy(s => s, StringComparer.OrdinalIgnoreCase).ToList(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShareAccessibleToUser(McdfShare share, IReadOnlyCollection<string> userGroups)
|
||||||
|
{
|
||||||
|
if (string.Equals(share.OwnerUID, UserUID, StringComparison.Ordinal)) return true;
|
||||||
|
|
||||||
|
bool allowedByUser = share.AllowedIndividuals.Any(i => string.Equals(i.AllowedIndividualUid, UserUID, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (allowedByUser) return true;
|
||||||
|
|
||||||
|
if (share.AllowedSyncshells.Count == 0) return false;
|
||||||
|
var allowedGroups = share.AllowedSyncshells.Select(g => g.AllowedGroupGid).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
return userGroups.Any(g => allowedGroups.Contains(g));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,6 +51,9 @@ public class MareDbContext : DbContext
|
|||||||
public DbSet<CharaDataOriginalFile> CharaDataOriginalFiles { get; set; }
|
public DbSet<CharaDataOriginalFile> CharaDataOriginalFiles { get; set; }
|
||||||
public DbSet<CharaDataPose> CharaDataPoses { get; set; }
|
public DbSet<CharaDataPose> CharaDataPoses { get; set; }
|
||||||
public DbSet<CharaDataAllowance> CharaDataAllowances { get; set; }
|
public DbSet<CharaDataAllowance> CharaDataAllowances { get; set; }
|
||||||
|
public DbSet<McdfShare> McdfShares { get; set; }
|
||||||
|
public DbSet<McdfShareAllowedUser> McdfShareAllowedUsers { get; set; }
|
||||||
|
public DbSet<McdfShareAllowedGroup> McdfShareAllowedGroups { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder mb)
|
protected override void OnModelCreating(ModelBuilder mb)
|
||||||
{
|
{
|
||||||
@@ -127,5 +130,28 @@ public class MareDbContext : DbContext
|
|||||||
mb.Entity<CharaDataAllowance>().HasIndex(c => c.ParentId);
|
mb.Entity<CharaDataAllowance>().HasIndex(c => c.ParentId);
|
||||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedGroup).WithMany().HasForeignKey(u => u.AllowedGroupGID).OnDelete(DeleteBehavior.Cascade);
|
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedGroup).WithMany().HasForeignKey(u => u.AllowedGroupGID).OnDelete(DeleteBehavior.Cascade);
|
||||||
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedUser).WithMany().HasForeignKey(u => u.AllowedUserUID).OnDelete(DeleteBehavior.Cascade);
|
mb.Entity<CharaDataAllowance>().HasOne(u => u.AllowedUser).WithMany().HasForeignKey(u => u.AllowedUserUID).OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
mb.Entity<McdfShare>().ToTable("mcdf_shares");
|
||||||
|
mb.Entity<McdfShare>().HasIndex(s => s.OwnerUID);
|
||||||
|
mb.Entity<McdfShare>().HasOne(s => s.Owner).WithMany().HasForeignKey(s => s.OwnerUID).OnDelete(DeleteBehavior.Cascade);
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.Description).HasColumnType("text");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.CipherData).HasColumnType("bytea");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.Nonce).HasColumnType("bytea");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.Salt).HasColumnType("bytea");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.Tag).HasColumnType("bytea");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.CreatedUtc).HasColumnType("timestamp with time zone");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.UpdatedUtc).HasColumnType("timestamp with time zone");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.ExpiresAtUtc).HasColumnType("timestamp with time zone");
|
||||||
|
mb.Entity<McdfShare>().Property(s => s.DownloadCount).HasColumnType("integer");
|
||||||
|
mb.Entity<McdfShare>().HasMany(s => s.AllowedIndividuals).WithOne(a => a.Share).HasForeignKey(a => a.ShareId).OnDelete(DeleteBehavior.Cascade);
|
||||||
|
mb.Entity<McdfShare>().HasMany(s => s.AllowedSyncshells).WithOne(a => a.Share).HasForeignKey(a => a.ShareId).OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
mb.Entity<McdfShareAllowedUser>().ToTable("mcdf_share_allowed_users");
|
||||||
|
mb.Entity<McdfShareAllowedUser>().HasKey(u => new { u.ShareId, u.AllowedIndividualUid });
|
||||||
|
mb.Entity<McdfShareAllowedUser>().HasIndex(u => u.AllowedIndividualUid);
|
||||||
|
|
||||||
|
mb.Entity<McdfShareAllowedGroup>().ToTable("mcdf_share_allowed_groups");
|
||||||
|
mb.Entity<McdfShareAllowedGroup>().HasKey(g => new { g.ShareId, g.AllowedGroupGid });
|
||||||
|
mb.Entity<McdfShareAllowedGroup>().HasIndex(g => g.AllowedGroupGid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class SyncshellDiscovery : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "auto_detect_visible",
|
||||||
|
table: "groups",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "password_temporarily_disabled",
|
||||||
|
table: "groups",
|
||||||
|
type: "boolean",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "auto_detect_visible",
|
||||||
|
table: "groups");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "password_temporarily_disabled",
|
||||||
|
table: "groups");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace MareSynchronosServer.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class McdfShare : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "mcdf_shares",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
owner_uid = table.Column<string>(type: "character varying(10)", nullable: false),
|
||||||
|
description = table.Column<string>(type: "text", nullable: false),
|
||||||
|
cipher_data = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||||
|
nonce = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||||
|
salt = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||||
|
tag = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||||
|
created_utc = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
updated_utc = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
expires_at_utc = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||||
|
download_count = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_mcdf_shares", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_mcdf_shares_users_owner_uid",
|
||||||
|
column: x => x.owner_uid,
|
||||||
|
principalTable: "users",
|
||||||
|
principalColumn: "uid",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "mcdf_share_allowed_groups",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
share_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
allowed_group_gid = table.Column<string>(type: "character varying(20)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_mcdf_share_allowed_groups", x => new { x.share_id, x.allowed_group_gid });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_mcdf_share_allowed_groups_mcdf_shares_share_id",
|
||||||
|
column: x => x.share_id,
|
||||||
|
principalTable: "mcdf_shares",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "mcdf_share_allowed_users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
share_id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||||
|
allowed_individual_uid = table.Column<string>(type: "character varying(10)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_mcdf_share_allowed_users", x => new { x.share_id, x.allowed_individual_uid });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_mcdf_share_allowed_users_mcdf_shares_share_id",
|
||||||
|
column: x => x.share_id,
|
||||||
|
principalTable: "mcdf_shares",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_mcdf_share_allowed_groups_allowed_group_gid",
|
||||||
|
table: "mcdf_share_allowed_groups",
|
||||||
|
column: "allowed_group_gid");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_mcdf_share_allowed_users_allowed_individual_uid",
|
||||||
|
table: "mcdf_share_allowed_users",
|
||||||
|
column: "allowed_individual_uid");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_mcdf_shares_owner_uid",
|
||||||
|
table: "mcdf_shares",
|
||||||
|
column: "owner_uid");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "mcdf_share_allowed_groups");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "mcdf_share_allowed_users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "mcdf_shares");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -454,6 +454,10 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("disable_vfx");
|
.HasColumnName("disable_vfx");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoDetectVisible")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("auto_detect_visible");
|
||||||
|
|
||||||
b.Property<string>("HashedPassword")
|
b.Property<string>("HashedPassword")
|
||||||
.HasColumnType("text")
|
.HasColumnType("text")
|
||||||
.HasColumnName("hashed_password");
|
.HasColumnName("hashed_password");
|
||||||
@@ -462,10 +466,22 @@ namespace MareSynchronosServer.Migrations
|
|||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("is_temporary");
|
.HasColumnName("is_temporary");
|
||||||
|
|
||||||
|
b.Property<bool>("PasswordTemporarilyDisabled")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("password_temporarily_disabled");
|
||||||
|
|
||||||
b.Property<bool>("InvitesEnabled")
|
b.Property<bool>("InvitesEnabled")
|
||||||
.HasColumnType("boolean")
|
.HasColumnType("boolean")
|
||||||
.HasColumnName("invites_enabled");
|
.HasColumnName("invites_enabled");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoDetectVisible")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("auto_detect_visible");
|
||||||
|
|
||||||
|
b.Property<bool>("PasswordTemporarilyDisabled")
|
||||||
|
.HasColumnType("boolean")
|
||||||
|
.HasColumnName("password_temporarily_disabled");
|
||||||
|
|
||||||
b.Property<string>("OwnerUID")
|
b.Property<string>("OwnerUID")
|
||||||
.HasColumnType("character varying(10)")
|
.HasColumnType("character varying(10)")
|
||||||
.HasColumnName("owner_uid");
|
.HasColumnName("owner_uid");
|
||||||
@@ -479,6 +495,99 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.ToTable("groups", (string)null);
|
b.ToTable("groups", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("Id")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
b.Property<byte[]>("CipherData")
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasColumnName("cipher_data");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedUtc")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("created_utc");
|
||||||
|
|
||||||
|
b.Property<int>("DownloadCount")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("download_count");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("description");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpiresAtUtc")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("expires_at_utc");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Nonce")
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasColumnName("nonce");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerUID")
|
||||||
|
.HasColumnType("character varying(10)")
|
||||||
|
.HasColumnName("owner_uid");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Salt")
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasColumnName("salt");
|
||||||
|
|
||||||
|
b.Property<byte[]>("Tag")
|
||||||
|
.HasColumnType("bytea")
|
||||||
|
.HasColumnName("tag");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedUtc")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("updated_utc");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_mcdf_shares");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerUID")
|
||||||
|
.HasDatabaseName("ix_mcdf_shares_owner_uid");
|
||||||
|
|
||||||
|
b.ToTable("mcdf_shares", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShareAllowedGroup", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("ShareId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("share_id");
|
||||||
|
|
||||||
|
b.Property<string>("AllowedGroupGid")
|
||||||
|
.HasColumnType("character varying(20)")
|
||||||
|
.HasColumnName("allowed_group_gid");
|
||||||
|
|
||||||
|
b.HasKey("ShareId", "AllowedGroupGid")
|
||||||
|
.HasName("pk_mcdf_share_allowed_groups");
|
||||||
|
|
||||||
|
b.HasIndex("AllowedGroupGid")
|
||||||
|
.HasDatabaseName("ix_mcdf_share_allowed_groups_allowed_group_gid");
|
||||||
|
|
||||||
|
b.ToTable("mcdf_share_allowed_groups", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShareAllowedUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("ShareId")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("share_id");
|
||||||
|
|
||||||
|
b.Property<string>("AllowedIndividualUid")
|
||||||
|
.HasColumnType("character varying(10)")
|
||||||
|
.HasColumnName("allowed_individual_uid");
|
||||||
|
|
||||||
|
b.HasKey("ShareId", "AllowedIndividualUid")
|
||||||
|
.HasName("pk_mcdf_share_allowed_users");
|
||||||
|
|
||||||
|
b.HasIndex("AllowedIndividualUid")
|
||||||
|
.HasDatabaseName("ix_mcdf_share_allowed_users_allowed_individual_uid");
|
||||||
|
|
||||||
|
b.ToTable("mcdf_share_allowed_users", (string)null);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.GroupBan", b =>
|
||||||
{
|
{
|
||||||
b.Property<string>("GroupGID")
|
b.Property<string>("GroupGID")
|
||||||
@@ -745,6 +854,13 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.Navigation("User");
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShare", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AllowedIndividuals");
|
||||||
|
|
||||||
|
b.Navigation("AllowedSyncshells");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.CharaData", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.CharaData", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
b.HasOne("MareSynchronosShared.Models.User", "Uploader")
|
||||||
@@ -943,6 +1059,42 @@ namespace MareSynchronosServer.Migrations
|
|||||||
b.Navigation("Group");
|
b.Navigation("Group");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("MareSynchronosShared.Models.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerUID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_mcdf_shares_users_owner_uid");
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShareAllowedGroup", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("MareSynchronosShared.Models.McdfShare", "Share")
|
||||||
|
.WithMany("AllowedSyncshells")
|
||||||
|
.HasForeignKey("ShareId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_mcdf_share_allowed_groups_mcdf_shares_share_id");
|
||||||
|
|
||||||
|
b.Navigation("Share");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("MareSynchronosShared.Models.McdfShareAllowedUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("MareSynchronosShared.Models.McdfShare", "Share")
|
||||||
|
.WithMany("AllowedIndividuals")
|
||||||
|
.HasForeignKey("ShareId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_mcdf_share_allowed_users_mcdf_shares_share_id");
|
||||||
|
|
||||||
|
b.Navigation("Share");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
modelBuilder.Entity("MareSynchronosShared.Models.LodeStoneAuth", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("MareSynchronosShared.Models.User", "User")
|
b.HasOne("MareSynchronosShared.Models.User", "User")
|
||||||
|
|||||||
@@ -19,4 +19,6 @@ public class Group
|
|||||||
public bool DisableVFX { get; set; }
|
public bool DisableVFX { get; set; }
|
||||||
public bool IsTemporary { get; set; }
|
public bool IsTemporary { get; set; }
|
||||||
public DateTime? ExpiresAt { get; set; }
|
public DateTime? ExpiresAt { get; set; }
|
||||||
|
public bool AutoDetectVisible { get; set; }
|
||||||
|
public bool PasswordTemporarilyDisabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace MareSynchronosShared.Models;
|
||||||
|
|
||||||
|
public class McdfShare
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
[MaxLength(10)]
|
||||||
|
public string OwnerUID { get; set; } = string.Empty;
|
||||||
|
public User Owner { get; set; } = null!;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
public byte[] CipherData { get; set; } = Array.Empty<byte>();
|
||||||
|
public byte[] Nonce { get; set; } = Array.Empty<byte>();
|
||||||
|
public byte[] Salt { get; set; } = Array.Empty<byte>();
|
||||||
|
public byte[] Tag { get; set; } = Array.Empty<byte>();
|
||||||
|
public DateTime CreatedUtc { get; set; }
|
||||||
|
public DateTime? UpdatedUtc { get; set; }
|
||||||
|
public DateTime? ExpiresAtUtc { get; set; }
|
||||||
|
public int DownloadCount { get; set; }
|
||||||
|
public ICollection<McdfShareAllowedUser> AllowedIndividuals { get; set; } = new HashSet<McdfShareAllowedUser>();
|
||||||
|
public ICollection<McdfShareAllowedGroup> AllowedSyncshells { get; set; } = new HashSet<McdfShareAllowedGroup>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class McdfShareAllowedUser
|
||||||
|
{
|
||||||
|
public Guid ShareId { get; set; }
|
||||||
|
public McdfShare Share { get; set; } = null!;
|
||||||
|
[MaxLength(10)]
|
||||||
|
public string AllowedIndividualUid { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class McdfShareAllowedGroup
|
||||||
|
{
|
||||||
|
public Guid ShareId { get; set; }
|
||||||
|
public McdfShare Share { get; set; } = null!;
|
||||||
|
[MaxLength(20)]
|
||||||
|
public string AllowedGroupGid { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user