Add files via upload

This commit is contained in:
Zura
2025-08-21 21:24:29 +02:00
committed by GitHub
commit 9a8ffe093f
62 changed files with 1206 additions and 0 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Mare Synchronos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,37 @@
using MareSynchronos.API.Data.Enum;
using MessagePack;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public class CharacterData
{
public CharacterData()
{
DataHash = new(() =>
{
var json = JsonSerializer.Serialize(this);
#pragma warning disable SYSLIB0021 // Type or member is obsolete
using SHA256CryptoServiceProvider cryptoProvider = new();
#pragma warning restore SYSLIB0021 // Type or member is obsolete
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(json))).Replace("-", "", StringComparison.Ordinal);
});
}
public Dictionary<ObjectKind, string> CustomizePlusData { get; set; } = new();
[JsonIgnore]
public Lazy<string> DataHash { get; }
public Dictionary<ObjectKind, List<FileReplacementData>> FileReplacements { get; set; } = new();
public Dictionary<ObjectKind, string> GlamourerData { get; set; } = new();
public string HeelsData { get; set; } = string.Empty;
public string HonorificData { get; set; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public string MoodlesData { get; set; } = string.Empty;
public string PetNamesData { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,22 @@
namespace MareSynchronos.API.Data.Comparer;
public class GroupDataComparer : IEqualityComparer<GroupData>
{
private static GroupDataComparer _instance = new GroupDataComparer();
private GroupDataComparer()
{ }
public static GroupDataComparer Instance => _instance;
public bool Equals(GroupData? x, GroupData? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal);
}
public int GetHashCode(GroupData obj)
{
return obj.GID.GetHashCode();
}
}

View File

@@ -0,0 +1,24 @@
using MareSynchronos.API.Dto.Group;
namespace MareSynchronos.API.Data.Comparer;
public class GroupDtoComparer : IEqualityComparer<GroupDto>
{
private static GroupDtoComparer _instance = new GroupDtoComparer();
private GroupDtoComparer()
{ }
public static GroupDtoComparer Instance => _instance;
public bool Equals(GroupDto? x, GroupDto? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal);
}
public int GetHashCode(GroupDto obj)
{
return obj.Group.GID.GetHashCode();
}
}

View File

@@ -0,0 +1,24 @@
using MareSynchronos.API.Dto.Group;
namespace MareSynchronos.API.Data.Comparer;
public class GroupPairDtoComparer : IEqualityComparer<GroupPairDto>
{
private static GroupPairDtoComparer _instance = new();
private GroupPairDtoComparer()
{ }
public static GroupPairDtoComparer Instance => _instance;
public bool Equals(GroupPairDto? x, GroupPairDto? y)
{
if (x == null || y == null) return false;
return x.GID.Equals(y.GID, StringComparison.Ordinal) && x.UID.Equals(y.UID, StringComparison.Ordinal);
}
public int GetHashCode(GroupPairDto obj)
{
return HashCode.Combine(obj.Group.GID.GetHashCode(), obj.User.UID.GetHashCode());
}
}

View File

@@ -0,0 +1,22 @@
namespace MareSynchronos.API.Data.Comparer;
public class UserDataComparer : IEqualityComparer<UserData>
{
private static UserDataComparer _instance = new();
private UserDataComparer()
{ }
public static UserDataComparer Instance => _instance;
public bool Equals(UserData? x, UserData? y)
{
if (x == null || y == null) return false;
return x.UID.Equals(y.UID, StringComparison.Ordinal);
}
public int GetHashCode(UserData obj)
{
return obj.UID.GetHashCode();
}
}

View File

@@ -0,0 +1,24 @@
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.Data.Comparer;
public class UserDtoComparer : IEqualityComparer<UserDto>
{
private static UserDtoComparer _instance = new();
private UserDtoComparer()
{ }
public static UserDtoComparer Instance => _instance;
public bool Equals(UserDto? x, UserDto? y)
{
if (x == null || y == null) return false;
return x.User.UID.Equals(y.User.UID, StringComparison.Ordinal);
}
public int GetHashCode(UserDto obj)
{
return obj.User.UID.GetHashCode();
}
}

View File

@@ -0,0 +1,6 @@
namespace MareSynchronos.API.Data;
public class Constants
{
public const string IndividualKeyword = "//MARE//DIRECT";
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupPairUserInfo
{
None = 0x0,
IsModerator = 0x2,
IsPinned = 0x4
}

View File

@@ -0,0 +1,11 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupPermissions
{
NoneSet = 0x0,
PreferDisableAnimations = 0x1,
PreferDisableSounds = 0x2,
DisableInvites = 0x4,
PreferDisableVFX = 0x8,
}

View File

@@ -0,0 +1,11 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum GroupUserPreferredPermissions
{
NoneSet = 0x0,
Paused = 0x1,
DisableAnimations = 0x2,
DisableSounds = 0x4,
DisableVFX = 0x8,
}

View File

@@ -0,0 +1,8 @@
namespace MareSynchronos.API.Data.Enum;
public enum IndividualPairStatus
{
None,
OneSided,
Bidirectional
}

View File

@@ -0,0 +1,8 @@
namespace MareSynchronos.API.Data.Enum;
public enum MessageSeverity
{
Information,
Warning,
Error
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Data.Enum;
public enum ObjectKind
{
Player = 0,
MinionOrMount = 1,
Companion = 2,
Pet = 3,
}

View File

@@ -0,0 +1,12 @@
namespace MareSynchronos.API.Data.Enum;
[Flags]
public enum UserPermissions
{
NoneSet = 0,
Paused = 1,
DisableAnimations = 2,
DisableSounds = 4,
DisableVFX = 8,
Sticky = 16,
}

View File

@@ -0,0 +1,50 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupPermissionsExtensions
{
public static bool IsDisableInvites(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.DisableInvites);
}
public static bool IsPreferDisableAnimations(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.PreferDisableAnimations);
}
public static bool IsPreferDisableSounds(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.PreferDisableSounds);
}
public static bool IsPreferDisableVFX(this GroupPermissions perm)
{
return perm.HasFlag(GroupPermissions.PreferDisableVFX);
}
public static void SetDisableInvites(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.DisableInvites;
else perm &= ~GroupPermissions.DisableInvites;
}
public static void SetPreferDisableAnimations(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.PreferDisableAnimations;
else perm &= ~GroupPermissions.PreferDisableAnimations;
}
public static void SetPreferDisableSounds(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.PreferDisableSounds;
else perm &= ~GroupPermissions.PreferDisableSounds;
}
public static void SetPreferDisableVFX(this ref GroupPermissions perm, bool set)
{
if (set) perm |= GroupPermissions.PreferDisableVFX;
else perm &= ~GroupPermissions.PreferDisableVFX;
}
}

View File

@@ -0,0 +1,28 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupUserInfoExtensions
{
public static bool IsModerator(this GroupPairUserInfo info)
{
return info.HasFlag(GroupPairUserInfo.IsModerator);
}
public static bool IsPinned(this GroupPairUserInfo info)
{
return info.HasFlag(GroupPairUserInfo.IsPinned);
}
public static void SetModerator(this ref GroupPairUserInfo info, bool isModerator)
{
if (isModerator) info |= GroupPairUserInfo.IsModerator;
else info &= ~GroupPairUserInfo.IsModerator;
}
public static void SetPinned(this ref GroupPairUserInfo info, bool isPinned)
{
if (isPinned) info |= GroupPairUserInfo.IsPinned;
else info &= ~GroupPairUserInfo.IsPinned;
}
}

View File

@@ -0,0 +1,50 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class GroupUserPermissionsExtensions
{
public static bool IsDisableAnimations(this GroupUserPreferredPermissions perm)
{
return perm.HasFlag(GroupUserPreferredPermissions.DisableAnimations);
}
public static bool IsDisableSounds(this GroupUserPreferredPermissions perm)
{
return perm.HasFlag(GroupUserPreferredPermissions.DisableSounds);
}
public static bool IsDisableVFX(this GroupUserPreferredPermissions perm)
{
return perm.HasFlag(GroupUserPreferredPermissions.DisableVFX);
}
public static bool IsPaused(this GroupUserPreferredPermissions perm)
{
return perm.HasFlag(GroupUserPreferredPermissions.Paused);
}
public static void SetDisableAnimations(this ref GroupUserPreferredPermissions perm, bool set)
{
if (set) perm |= GroupUserPreferredPermissions.DisableAnimations;
else perm &= ~GroupUserPreferredPermissions.DisableAnimations;
}
public static void SetDisableSounds(this ref GroupUserPreferredPermissions perm, bool set)
{
if (set) perm |= GroupUserPreferredPermissions.DisableSounds;
else perm &= ~GroupUserPreferredPermissions.DisableSounds;
}
public static void SetDisableVFX(this ref GroupUserPreferredPermissions perm, bool set)
{
if (set) perm |= GroupUserPreferredPermissions.DisableVFX;
else perm &= ~GroupUserPreferredPermissions.DisableVFX;
}
public static void SetPaused(this ref GroupUserPreferredPermissions perm, bool set)
{
if (set) perm |= GroupUserPreferredPermissions.Paused;
else perm &= ~GroupUserPreferredPermissions.Paused;
}
}

View File

@@ -0,0 +1,61 @@
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.API.Data.Extensions;
public static class UserPermissionsExtensions
{
public static bool IsDisableAnimations(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableAnimations);
}
public static bool IsDisableSounds(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableSounds);
}
public static bool IsDisableVFX(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.DisableVFX);
}
public static bool IsPaused(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.Paused);
}
public static bool IsSticky(this UserPermissions perm)
{
return perm.HasFlag(UserPermissions.Sticky);
}
public static void SetDisableAnimations(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableAnimations;
else perm &= ~UserPermissions.DisableAnimations;
}
public static void SetDisableSounds(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableSounds;
else perm &= ~UserPermissions.DisableSounds;
}
public static void SetDisableVFX(this ref UserPermissions perm, bool set)
{
if (set) perm |= UserPermissions.DisableVFX;
else perm &= ~UserPermissions.DisableVFX;
}
public static void SetPaused(this ref UserPermissions perm, bool paused)
{
if (paused) perm |= UserPermissions.Paused;
else perm &= ~UserPermissions.Paused;
}
public static void SetSticky(this ref UserPermissions perm, bool sticky)
{
if (sticky) perm |= UserPermissions.Sticky;
else perm &= ~UserPermissions.Sticky;
}
}

View File

@@ -0,0 +1,29 @@
using MessagePack;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public class FileReplacementData
{
public FileReplacementData()
{
DataHash = new(() =>
{
var json = JsonSerializer.Serialize(this);
#pragma warning disable SYSLIB0021 // Type or member is obsolete
using SHA256CryptoServiceProvider cryptoProvider = new();
#pragma warning restore SYSLIB0021 // Type or member is obsolete
return BitConverter.ToString(cryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(json))).Replace("-", "", StringComparison.Ordinal);
});
}
[JsonIgnore]
public Lazy<string> DataHash { get; }
public string FileSwapPath { get; set; } = string.Empty;
public string[] GamePaths { get; set; } = Array.Empty<string>();
public string Hash { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,10 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupData(string GID, string? Alias = null)
{
[IgnoreMember]
public string AliasOrGID => string.IsNullOrWhiteSpace(Alias) ? GID : Alias;
}

View File

@@ -0,0 +1,10 @@
using MessagePack;
namespace MareSynchronos.API.Data;
[MessagePackObject(keyAsPropertyName: true)]
public record UserData(string UID, string? Alias = null)
{
[IgnoreMember]
public string AliasOrUID => string.IsNullOrWhiteSpace(Alias) ? UID : Alias;
}

View File

@@ -0,0 +1,9 @@
namespace MareSynchronos.API.Dto.CharaData;
public enum AccessTypeDto
{
Individuals,
ClosePairs,
AllPairs,
Public
}

View File

@@ -0,0 +1,14 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataDownloadDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public string GlamourerData { get; init; } = string.Empty;
public string CustomizeData { get; init; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public List<GamePathEntry> FileGamePaths { get; init; } = [];
public List<GamePathEntry> FileSwaps { get; init; } = [];
}

View File

@@ -0,0 +1,9 @@
using MareSynchronos.API.Data;
namespace MareSynchronos.API.Dto.CharaData;
public record CharaDataDto(string Id, UserData Uploader)
{
public string Description { get; init; } = string.Empty;
public DateTime UpdatedDate { get; init; }
}

View File

@@ -0,0 +1,88 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataFullDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public DateTime CreatedDate { get; init; }
public DateTime ExpiryDate { get; set; }
public string GlamourerData { get; set; } = string.Empty;
public string CustomizeData { get; set; } = string.Empty;
public string ManipulationData { get; set; } = string.Empty;
public int DownloadCount { get; set; } = 0;
public List<UserData> AllowedUsers { get; set; } = [];
public List<GroupData> AllowedGroups { get; set; } = [];
public List<GamePathEntry> FileGamePaths { get; set; } = [];
public List<GamePathEntry> FileSwaps { get; set; } = [];
public List<GamePathEntry> OriginalFiles { get; set; } = [];
public AccessTypeDto AccessType { get; set; }
public ShareTypeDto ShareType { get; set; }
public List<PoseEntry> PoseData { get; set; } = [];
}
[MessagePackObject(keyAsPropertyName: true)]
public record GamePathEntry(string HashOrFileSwap, string GamePath);
[MessagePackObject(keyAsPropertyName: true)]
public record PoseEntry(long? Id)
{
public string? Description { get; set; } = string.Empty;
public string? PoseData { get; set; } = string.Empty;
public WorldData? WorldData { get; set; }
}
[MessagePackObject]
public record struct WorldData
{
[Key(0)] public LocationInfo LocationInfo { get; set; }
[Key(1)] public float PositionX { get; set; }
[Key(2)] public float PositionY { get; set; }
[Key(3)] public float PositionZ { get; set; }
[Key(4)] public float RotationX { get; set; }
[Key(5)] public float RotationY { get; set; }
[Key(6)] public float RotationZ { get; set; }
[Key(7)] public float RotationW { get; set; }
[Key(8)] public float ScaleX { get; set; }
[Key(9)] public float ScaleY { get; set; }
[Key(10)] public float ScaleZ { get; set; }
}
[MessagePackObject]
public record struct LocationInfo
{
[Key(0)] public uint ServerId { get; set; }
[Key(1)] public uint MapId { get; set; }
[Key(2)] public uint TerritoryId { get; set; }
[Key(3)] public uint DivisionId { get; set; }
[Key(4)] public uint WardId { get; set; }
[Key(5)] public uint HouseId { get; set; }
[Key(6)] public uint RoomId { get; set; }
}
[MessagePackObject]
public record struct PoseData
{
[Key(0)] public bool IsDelta { get; set; }
[Key(1)] public Dictionary<string, BoneData> Bones { get; set; }
[Key(2)] public Dictionary<string, BoneData> MainHand { get; set; }
[Key(3)] public Dictionary<string, BoneData> OffHand { get; set; }
[Key(4)] public BoneData ModelDifference { get; set; }
}
[MessagePackObject]
public record struct BoneData
{
[Key(0)] public bool Exists { get; set; }
[Key(1)] public float PositionX { get; set; }
[Key(2)] public float PositionY { get; set; }
[Key(3)] public float PositionZ { get; set; }
[Key(4)] public float RotationX { get; set; }
[Key(5)] public float RotationY { get; set; }
[Key(6)] public float RotationZ { get; set; }
[Key(7)] public float RotationW { get; set; }
[Key(8)] public float ScaleX { get; set; }
[Key(9)] public float ScaleY { get; set; }
[Key(10)] public float ScaleZ { get; set; }
}

View File

@@ -0,0 +1,11 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataMetaInfoDto(string Id, UserData Uploader) : CharaDataDto(Id, Uploader)
{
public bool CanBeDownloaded { get; init; }
public List<PoseEntry> PoseData { get; set; } = [];
}

View File

@@ -0,0 +1,20 @@
using MessagePack;
namespace MareSynchronos.API.Dto.CharaData;
[MessagePackObject(keyAsPropertyName: true)]
public record CharaDataUpdateDto(string Id)
{
public string? Description { get; set; }
public DateTime? ExpiryDate { get; set; }
public string? GlamourerData { get; set; }
public string? CustomizeData { get; set; }
public string? ManipulationData { get; set; }
public List<string>? AllowedUsers { get; set; }
public List<string>? AllowedGroups { get; set; }
public List<GamePathEntry>? FileGamePaths { get; set; }
public List<GamePathEntry>? FileSwaps { get; set; }
public AccessTypeDto? AccessType { get; set; }
public ShareTypeDto? ShareType { get; set; }
public List<PoseEntry>? Poses { get; set; }
}

View File

@@ -0,0 +1,7 @@
namespace MareSynchronos.API.Dto.CharaData;
public enum ShareTypeDto
{
Private,
Shared
}

View File

@@ -0,0 +1,27 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record ConnectionDto(UserData User)
{
public Version CurrentClientVersion { get; set; } = new(0, 0, 0);
public int ServerVersion { get; set; }
public bool IsAdmin { get; set; }
public bool IsModerator { get; set; }
public ServerInfo ServerInfo { get; set; } = new();
public DefaultPermissionsDto DefaultPreferredPermissions { get; set; } = new();
}
[MessagePackObject(keyAsPropertyName: true)]
public record ServerInfo
{
public string ShardName { get; set; } = string.Empty;
public int MaxGroupUserCount { get; set; }
public int MaxGroupsCreatedByUser { get; set; }
public int MaxGroupsJoinedByUser { get; set; }
public Uri FileServerAddress { get; set; } = new Uri("http://nonemptyuri");
public int MaxCharaData { get; set; }
public int MaxCharaDataVanity { get; set; }
}

View File

@@ -0,0 +1,15 @@
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record DefaultPermissionsDto
{
public bool DisableIndividualAnimations { get; set; } = false;
public bool DisableIndividualSounds { get; set; } = false;
public bool DisableIndividualVFX { get; set; } = false;
public bool DisableGroupAnimations { get; set; } = false;
public bool DisableGroupSounds { get; set; } = false;
public bool DisableGroupVFX { get; set; } = false;
public bool IndividualIsSticky { get; set; } = true;
}

View File

@@ -0,0 +1,15 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Files;
[MessagePackObject(keyAsPropertyName: true)]
public record DownloadFileDto : ITransferFileDto
{
public bool FileExists { get; set; } = true;
public string Hash { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public long Size { get; set; } = 0;
public bool IsForbidden { get; set; } = false;
public string ForbiddenBy { get; set; } = string.Empty;
public long RawSize { get; set; } = 0;
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MareSynchronos.API.Dto.Files;
public class FilesSendDto
{
public List<string> FileHashes { get; set; } = new();
public List<string> UIDs { get; set; } = new();
}

View File

@@ -0,0 +1,8 @@
namespace MareSynchronos.API.Dto.Files;
public interface ITransferFileDto
{
string ForbiddenBy { get; set; }
string Hash { get; set; }
bool IsForbidden { get; set; }
}

View File

@@ -0,0 +1,11 @@
using MessagePack;
namespace MareSynchronos.API.Dto.Files;
[MessagePackObject(keyAsPropertyName: true)]
public record UploadFileDto : ITransferFileDto
{
public string Hash { get; set; } = string.Empty;
public bool IsForbidden { get; set; } = false;
public string ForbiddenBy { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,19 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record BannedGroupUserDto : GroupPairDto
{
public BannedGroupUserDto(GroupData group, UserData user, string reason, DateTime bannedOn, string bannedBy) : base(group, user)
{
Reason = reason;
BannedOn = bannedOn;
BannedBy = bannedBy;
}
public string Reason { get; set; }
public DateTime BannedOn { get; set; }
public string BannedBy { get; set; }
}

View File

@@ -0,0 +1,13 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupDto(GroupData Group)
{
public GroupData Group { get; set; } = Group;
public string GID => Group.GID;
public string? GroupAlias => Group.Alias;
public string GroupAliasOrGID => Group.AliasOrGID;
}

View File

@@ -0,0 +1,14 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupFullInfoDto(GroupData Group, UserData Owner, GroupPermissions GroupPermissions,
GroupUserPreferredPermissions GroupUserPermissions, GroupPairUserInfo GroupUserInfo,
Dictionary<string, GroupPairUserInfo> GroupPairUserInfos) : GroupInfoDto(Group, Owner, GroupPermissions)
{
public GroupUserPreferredPermissions GroupUserPermissions { get; set; } = GroupUserPermissions;
public GroupPairUserInfo GroupUserInfo { get; set; } = GroupUserInfo;
}

View File

@@ -0,0 +1,18 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupInfoDto(GroupData Group, UserData Owner, GroupPermissions GroupPermissions) : GroupDto(Group)
{
public GroupPermissions GroupPermissions { get; set; } = GroupPermissions;
public UserData Owner { get; set; } = Owner;
public string OwnerUID => Owner.UID;
public string? OwnerAlias => Owner.Alias;
public string OwnerAliasOrUID => Owner.AliasOrUID;
}
public record GroupJoinInfoDto(GroupData Group, UserData Owner, GroupPermissions GroupPermissions, bool Success) : GroupInfoDto(Group, Owner, GroupPermissions);

View File

@@ -0,0 +1,11 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPasswordDto(GroupData Group, string Password) : GroupDto(Group);
[MessagePackObject(keyAsPropertyName: true)]
public record GroupJoinDto(GroupData Group, string Password, GroupUserPreferredPermissions GroupUserPreferredPermissions) : GroupPasswordDto(Group, Password);

View File

@@ -0,0 +1,12 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairDto(GroupData Group, UserData User) : GroupDto(Group)
{
public string UID => User.UID;
public string? UserAlias => User.Alias;
public string UserAliasOrUID => User.AliasOrUID;
}

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairFullInfoDto(GroupData Group, UserData User, UserPermissions SelfToOtherPermissions, UserPermissions OtherToSelfPermissions) : GroupPairDto(Group, User);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairUserInfoDto(GroupData Group, UserData User, GroupPairUserInfo GroupUserInfo) : GroupPairDto(Group, User);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPairUserPermissionDto(GroupData Group, UserData User, GroupUserPreferredPermissions GroupPairPermissions) : GroupPairDto(Group, User);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.Group;
[MessagePackObject(keyAsPropertyName: true)]
public record GroupPermissionDto(GroupData Group, GroupPermissions Permissions) : GroupDto(Group);

View File

@@ -0,0 +1,9 @@
using MessagePack;
namespace MareSynchronos.API.Dto;
[MessagePackObject(keyAsPropertyName: true)]
public record SystemInfoDto
{
public int OnlineUsers { get; set; }
}

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record BulkPermissionsDto(Dictionary<string, UserPermissions> AffectedUsers, Dictionary<string, GroupUserPreferredPermissions> AffectedGroups);

View File

@@ -0,0 +1,6 @@
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record CensusDataDto(ushort WorldId, short RaceId, short TribeId, short Gender);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record OnlineUserCharaDataDto(UserData User, CharacterData CharaData) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record OnlineUserIdentDto(UserData User, string Ident) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserCharaDataMessageDto(List<UserData> Recipients, CharacterData CharaData, CensusDataDto? CensusDataDto);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserDto(UserData User);

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserIndividualPairStatusDto(UserData User, IndividualPairStatus IndividualPairStatus) : UserDto(User);

View File

@@ -0,0 +1,21 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserFullPairDto(UserData User, IndividualPairStatus IndividualPairStatus, List<string> Groups, UserPermissions OwnPermissions, UserPermissions OtherPermissions) : UserDto(User)
{
public UserPermissions OwnPermissions { get; set; } = OwnPermissions;
public UserPermissions OtherPermissions { get; set; } = OtherPermissions;
public IndividualPairStatus IndividualPairStatus { get; set; } = IndividualPairStatus;
}
[MessagePackObject(keyAsPropertyName: true)]
public record UserPairDto(UserData User, IndividualPairStatus IndividualPairStatus, UserPermissions OwnPermissions, UserPermissions OtherPermissions) : UserDto(User)
{
public UserPermissions OwnPermissions { get; set; } = OwnPermissions;
public UserPermissions OtherPermissions { get; set; } = OtherPermissions;
public IndividualPairStatus IndividualPairStatus { get; set; } = IndividualPairStatus;
}

View File

@@ -0,0 +1,8 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserPermissionsDto(UserData User, UserPermissions Permissions) : UserDto(User);

View File

@@ -0,0 +1,7 @@
using MareSynchronos.API.Data;
using MessagePack;
namespace MareSynchronos.API.Dto.User;
[MessagePackObject(keyAsPropertyName: true)]
public record UserProfileDto(UserData User, bool Disabled, bool? IsNSFW, string? ProfilePictureBase64, string? Description) : UserDto(User);

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack.Annotations" Version="3.1.3" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32602.215
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "MareSynchronos.API.csproj", "{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD05EE19-802F-4490-AAD8-CAD4BF1D630D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DFB70C71-AB27-468D-A08B-218CA79BF69D}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,23 @@
namespace MareSynchronos.API.Routes;
public class MareAuth
{
public const string OAuth = "/oauth";
public const string Auth = "/auth";
public const string Auth_CreateIdent = "createWithIdent";
public const string Auth_RenewToken = "renewToken";
public const string OAuth_GetUIDsBasedOnSecretKeys = "getUIDsViaSecretKey";
public const string OAuth_CreateOAuth = "createWithOAuth";
public const string OAuth_RenewOAuthToken = "renewToken";
public const string OAuth_GetDiscordOAuthEndpoint = "getDiscordOAuthEndpoint";
public const string OAuth_GetUIDs = "getUIDs";
public const string OAuth_GetDiscordOAuthToken = "getDiscordOAuthToken";
public static Uri AuthFullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_CreateIdent);
public static Uri AuthWithOauthFullPath(Uri baseUri) => new Uri(baseUri, OAuth + "/" + OAuth_CreateOAuth);
public static Uri RenewTokenFullPath(Uri baseUri) => new Uri(baseUri, Auth + "/" + Auth_RenewToken);
public static Uri RenewOAuthTokenFullPath(Uri baseUri) => new Uri(baseUri, OAuth + "/" + OAuth_RenewOAuthToken);
public static Uri GetUIDsBasedOnSecretKeyFullPath(Uri baseUri) => new Uri(baseUri, OAuth + "/" + OAuth_GetUIDsBasedOnSecretKeys);
public static Uri GetDiscordOAuthEndpointFullPath(Uri baseUri) => new Uri(baseUri, OAuth + "/" + OAuth_GetDiscordOAuthEndpoint);
public static Uri GetDiscordOAuthTokenFullPath(Uri baseUri, string sessionId) => new Uri(baseUri, OAuth + "/" + OAuth_GetDiscordOAuthToken + "?sessionId=" + sessionId);
public static Uri GetUIDsFullPath(Uri baseUri) => new Uri(baseUri, OAuth + "/" + OAuth_GetUIDs);
}

View File

@@ -0,0 +1,47 @@
namespace MareSynchronos.API.Routes;
public class MareFiles
{
public const string Cache = "/cache";
public const string Cache_Get = "get";
public const string Request = "/request";
public const string Request_Cancel = "cancel";
public const string Request_Check = "check";
public const string Request_Enqueue = "enqueue";
public const string Request_RequestFile = "file";
public const string ServerFiles = "/files";
public const string ServerFiles_DeleteAll = "deleteAll";
public const string ServerFiles_FilesSend = "filesSend";
public const string ServerFiles_GetSizes = "getFileSizes";
public const string ServerFiles_Upload = "upload";
public const string ServerFiles_UploadMunged = "uploadMunged";
public const string ServerFiles_DownloadServers = "downloadServers";
public const string Distribution = "/dist";
public const string Distribution_Get = "get";
public const string Main = "/main";
public const string Main_SendReady = "sendReady";
public const string Speedtest = "/speedtest";
public const string Speedtest_Run = "run";
public static Uri CacheGetFullPath(Uri baseUri, Guid requestId) => new(baseUri, Cache + "/" + Cache_Get + "?requestId=" + requestId.ToString());
public static Uri RequestCancelFullPath(Uri baseUri, Guid guid) => new Uri(baseUri, Request + "/" + Request_Cancel + "?requestId=" + guid.ToString());
public static Uri RequestCheckQueueFullPath(Uri baseUri, Guid guid) => new Uri(baseUri, Request + "/" + Request_Check + "?requestId=" + guid.ToString());
public static Uri RequestEnqueueFullPath(Uri baseUri) => new(baseUri, Request + "/" + Request_Enqueue);
public static Uri RequestRequestFileFullPath(Uri baseUri, string hash) => new(baseUri, Request + "/" + Request_RequestFile + "?file=" + hash);
public static Uri ServerFilesDeleteAllFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_DeleteAll);
public static Uri ServerFilesFilesSendFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_FilesSend);
public static Uri ServerFilesGetSizesFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_GetSizes);
public static Uri ServerFilesUploadFullPath(Uri baseUri, string hash) => new(baseUri, ServerFiles + "/" + ServerFiles_Upload + "/" + hash);
public static Uri ServerFilesUploadMunged(Uri baseUri, string hash) => new(baseUri, ServerFiles + "/" + ServerFiles_UploadMunged + "/" + hash);
public static Uri ServerFilesGetDownloadServersFullPath(Uri baseUri) => new(baseUri, ServerFiles + "/" + ServerFiles_DownloadServers);
public static Uri DistributionGetFullPath(Uri baseUri, string hash) => new(baseUri, Distribution + "/" + Distribution_Get + "?file=" + hash);
public static Uri SpeedtestRunFullPath(Uri baseUri) => new(baseUri, Speedtest + "/" + Speedtest_Run);
public static Uri MainSendReadyFullPath(Uri baseUri, string uid, Guid request) => new(baseUri, Main + "/" + Main_SendReady + "/" + "?uid=" + uid + "&requestId=" + request.ToString());
}

View File

@@ -0,0 +1,91 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MareSynchronos.API.Dto;
using MareSynchronos.API.Dto.CharaData;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.SignalR;
public interface IMareHub
{
const int ApiVersion = 33;
const string Path = "/mare";
Task<bool> CheckClientHealth();
Task Client_DownloadReady(Guid requestId);
Task Client_GroupChangePermissions(GroupPermissionDto groupPermission);
Task Client_GroupDelete(GroupDto groupDto);
Task Client_GroupPairChangeUserInfo(GroupPairUserInfoDto userInfo);
Task Client_GroupPairJoined(GroupPairFullInfoDto groupPairInfoDto);
Task Client_GroupPairLeft(GroupPairDto groupPairDto);
Task Client_GroupSendFullInfo(GroupFullInfoDto groupInfo);
Task Client_GroupSendInfo(GroupInfoDto groupInfo);
Task Client_ReceiveServerMessage(MessageSeverity messageSeverity, string message);
Task Client_UpdateSystemInfo(SystemInfoDto systemInfo);
Task Client_UserAddClientPair(UserPairDto dto);
Task Client_UserReceiveCharacterData(OnlineUserCharaDataDto dataDto);
Task Client_UserReceiveUploadStatus(UserDto dto);
Task Client_UserRemoveClientPair(UserDto dto);
Task Client_UserSendOffline(UserDto dto);
Task Client_UserSendOnline(OnlineUserIdentDto dto);
Task Client_UserUpdateOtherPairPermissions(UserPermissionsDto dto);
Task Client_UpdateUserIndividualPairStatusDto(UserIndividualPairStatusDto dto);
Task Client_UserUpdateProfile(UserDto dto);
Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto);
Task Client_UserUpdateDefaultPermissions(DefaultPermissionsDto dto);
Task Client_GroupChangeUserPairPermissions(GroupPairUserPermissionDto dto);
Task Client_GposeLobbyJoin(UserData userData);
Task Client_GposeLobbyLeave(UserData userData);
Task Client_GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto);
Task Client_GposeLobbyPushPoseData(UserData userData, PoseData poseData);
Task Client_GposeLobbyPushWorldData(UserData userData, WorldData worldData);
Task<ConnectionDto> GetConnectionDto();
Task GroupBanUser(GroupPairDto dto, string reason);
Task GroupChangeGroupPermissionState(GroupPermissionDto dto);
Task GroupChangeOwnership(GroupPairDto groupPair);
Task<bool> GroupChangePassword(GroupPasswordDto groupPassword);
Task GroupClear(GroupDto group);
Task<GroupJoinDto> GroupCreate();
Task<List<string>> GroupCreateTempInvite(GroupDto group, int amount);
Task GroupDelete(GroupDto group);
Task<List<BannedGroupUserDto>> GroupGetBannedUsers(GroupDto group);
Task<GroupJoinInfoDto> GroupJoin(GroupPasswordDto passwordedGroup);
Task<bool> GroupJoinFinalize(GroupJoinDto passwordedGroup);
Task GroupLeave(GroupDto group);
Task GroupRemoveUser(GroupPairDto groupPair);
Task GroupSetUserInfo(GroupPairUserInfoDto groupPair);
Task<List<GroupFullInfoDto>> GroupsGetAll();
Task GroupUnbanUser(GroupPairDto groupPair);
Task<int> GroupPrune(GroupDto group, int days, bool execute);
Task UserAddPair(UserDto user);
Task UserDelete();
Task<List<OnlineUserIdentDto>> UserGetOnlinePairs(CensusDataDto? censusDataDto);
Task<List<UserFullPairDto>> UserGetPairedClients();
Task<UserProfileDto> UserGetProfile(UserDto dto);
Task UserPushData(UserCharaDataMessageDto dto);
Task UserRemovePair(UserDto userDto);
Task UserSetProfile(UserProfileDto userDescription);
Task UserUpdateDefaultPermissions(DefaultPermissionsDto defaultPermissionsDto);
Task SetBulkPermissions(BulkPermissionsDto dto);
Task<CharaDataFullDto?> CharaDataCreate();
Task<CharaDataFullDto?> CharaDataUpdate(CharaDataUpdateDto updateDto);
Task<bool> CharaDataDelete(string id);
Task<CharaDataMetaInfoDto?> CharaDataGetMetainfo(string id);
Task<CharaDataDownloadDto?> CharaDataDownload(string id);
Task<List<CharaDataFullDto>> CharaDataGetOwn();
Task<List<CharaDataMetaInfoDto>> CharaDataGetShared();
Task<CharaDataFullDto?> CharaDataAttemptRestore(string id);
Task<string> GposeLobbyCreate();
Task<List<UserData>> GposeLobbyJoin(string lobbyId);
Task<bool> GposeLobbyLeave();
Task GposeLobbyPushCharacterData(CharaDataDownloadDto charaDownloadDto);
Task GposeLobbyPushPoseData(PoseData poseData);
Task GposeLobbyPushWorldData(WorldData worldData);
}

View File

@@ -0,0 +1,61 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
using MareSynchronos.API.Dto;
using MareSynchronos.API.Dto.CharaData;
using MareSynchronos.API.Dto.Group;
using MareSynchronos.API.Dto.User;
namespace MareSynchronos.API.SignalR;
public interface IMareHubClient : IMareHub
{
void OnDownloadReady(Action<Guid> act);
void OnGroupChangePermissions(Action<GroupPermissionDto> act);
void OnGroupDelete(Action<GroupDto> act);
void OnGroupPairChangeUserInfo(Action<GroupPairUserInfoDto> act);
void OnGroupPairJoined(Action<GroupPairFullInfoDto> act);
void OnGroupPairLeft(Action<GroupPairDto> act);
void OnGroupSendFullInfo(Action<GroupFullInfoDto> act);
void OnGroupSendInfo(Action<GroupInfoDto> act);
void OnReceiveServerMessage(Action<MessageSeverity, string> act);
void OnUpdateSystemInfo(Action<SystemInfoDto> act);
void OnUserAddClientPair(Action<UserPairDto> act);
void OnUserReceiveCharacterData(Action<OnlineUserCharaDataDto> act);
void OnUserReceiveUploadStatus(Action<UserDto> act);
void OnUserRemoveClientPair(Action<UserDto> act);
void OnUserSendOffline(Action<UserDto> act);
void OnUserSendOnline(Action<OnlineUserIdentDto> act);
void OnUserUpdateOtherPairPermissions(Action<UserPermissionsDto> act);
void OnUserUpdateProfile(Action<UserDto> act);
void OnUserUpdateSelfPairPermissions(Action<UserPermissionsDto> act);
void OnUserDefaultPermissionUpdate(Action<DefaultPermissionsDto> act);
void OnUpdateUserIndividualPairStatusDto(Action<UserIndividualPairStatusDto> act);
void OnGroupChangeUserPairPermissions(Action<GroupPairUserPermissionDto> act);
void OnGposeLobbyJoin(Action<UserData> act);
void OnGposeLobbyLeave(Action<UserData> act);
void OnGposeLobbyPushCharacterData(Action<CharaDataDownloadDto> act);
void OnGposeLobbyPushPoseData(Action<UserData, PoseData> act);
void OnGposeLobbyPushWorldData(Action<UserData, WorldData> act);
}