Testing more garbage encryption
This commit is contained in:
@@ -58,6 +58,7 @@ public class DCGEDbContext : DbContext
|
||||
IEnumerable<string> pendingMigrations = Database.GetPendingMigrations();
|
||||
if (!pendingMigrations.Any())
|
||||
{
|
||||
_logger.LogDebug("No pending migrations found, continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
12
SVSim.Database/Enums/SocialAccountType.cs
Normal file
12
SVSim.Database/Enums/SocialAccountType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace SVSim.Database.Enums;
|
||||
|
||||
public enum SocialAccountType
|
||||
{
|
||||
None,
|
||||
GooglePlay,
|
||||
GameCenter,
|
||||
Facebook,
|
||||
Dmm,
|
||||
Steam,
|
||||
AppleId
|
||||
}
|
||||
171
SVSim.Database/Migrations/20240907191709_Initial.Designer.cs
generated
Normal file
171
SVSim.Database/Migrations/20240907191709_Initial.Designer.cs
generated
Normal file
@@ -0,0 +1,171 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using SVSim.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SVSim.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(SVSimDbContext))]
|
||||
[Migration("20240907191709_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.8");
|
||||
|
||||
modelBuilder.Entity("DCGEngine.Database.Models.CardEntry", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Attack")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Defense")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.IsRequired()
|
||||
.HasMaxLength(21)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("PrimaryResourceCost")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("ShadowverseDeckEntryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShadowverseDeckEntryId");
|
||||
|
||||
b.ToTable("CardEntry");
|
||||
|
||||
b.HasDiscriminator().HasValue("CardEntry");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ShadowverseDeckEntry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.SocialAccountConnection", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("AccountId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AccountType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ViewerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ViewerId");
|
||||
|
||||
b.ToTable("SocialAccountConnection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.Viewer", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ShortUdid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Viewer");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardEntry", b =>
|
||||
{
|
||||
b.HasBaseType("DCGEngine.Database.Models.CardEntry");
|
||||
|
||||
b.HasDiscriminator().HasValue("ShadowverseCardEntry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DCGEngine.Database.Models.CardEntry", b =>
|
||||
{
|
||||
b.HasOne("SVSim.Database.Models.ShadowverseDeckEntry", null)
|
||||
.WithMany("Cards")
|
||||
.HasForeignKey("ShadowverseDeckEntryId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.SocialAccountConnection", b =>
|
||||
{
|
||||
b.HasOne("SVSim.Database.Models.Viewer", "Viewer")
|
||||
.WithMany()
|
||||
.HasForeignKey("ViewerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Viewer");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b =>
|
||||
{
|
||||
b.Navigation("Cards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
118
SVSim.Database/Migrations/20240907191709_Initial.cs
Normal file
118
SVSim.Database/Migrations/20240907191709_Initial.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SVSim.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ShadowverseDeckEntry",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
DateCreated = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
DateUpdated = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
InternalName = table.Column<string>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ShadowverseDeckEntry", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Viewer",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
DisplayName = table.Column<string>(type: "TEXT", nullable: false),
|
||||
ShortUdid = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DateCreated = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
DateUpdated = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Viewer", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CardEntry",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
InternalName = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Attack = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Defense = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
PrimaryResourceCost = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Discriminator = table.Column<string>(type: "TEXT", maxLength: 21, nullable: false),
|
||||
ShadowverseDeckEntryId = table.Column<long>(type: "INTEGER", nullable: true),
|
||||
DateCreated = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
DateUpdated = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_CardEntry", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_CardEntry_ShadowverseDeckEntry_ShadowverseDeckEntryId",
|
||||
column: x => x.ShadowverseDeckEntryId,
|
||||
principalTable: "ShadowverseDeckEntry",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "SocialAccountConnection",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "TEXT", nullable: false),
|
||||
AccountType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
AccountId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ViewerId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DateCreated = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
DateUpdated = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_SocialAccountConnection", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_SocialAccountConnection_Viewer_ViewerId",
|
||||
column: x => x.ViewerId,
|
||||
principalTable: "Viewer",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_CardEntry_ShadowverseDeckEntryId",
|
||||
table: "CardEntry",
|
||||
column: "ShadowverseDeckEntryId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SocialAccountConnection_ViewerId",
|
||||
table: "SocialAccountConnection",
|
||||
column: "ViewerId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "CardEntry");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "SocialAccountConnection");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ShadowverseDeckEntry");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Viewer");
|
||||
}
|
||||
}
|
||||
}
|
||||
168
SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs
Normal file
168
SVSim.Database/Migrations/SVSimDbContextModelSnapshot.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using SVSim.Database;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SVSim.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(SVSimDbContext))]
|
||||
partial class SVSimDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.8");
|
||||
|
||||
modelBuilder.Entity("DCGEngine.Database.Models.CardEntry", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Attack")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("Defense")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.IsRequired()
|
||||
.HasMaxLength(21)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int?>("PrimaryResourceCost")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long?>("ShadowverseDeckEntryId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShadowverseDeckEntryId");
|
||||
|
||||
b.ToTable("CardEntry");
|
||||
|
||||
b.HasDiscriminator().HasValue("CardEntry");
|
||||
|
||||
b.UseTphMappingStrategy();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("InternalName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ShadowverseDeckEntry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.SocialAccountConnection", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("AccountId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AccountType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ViewerId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ViewerId");
|
||||
|
||||
b.ToTable("SocialAccountConnection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.Viewer", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateCreated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("DateUpdated")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ShortUdid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Viewer");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseCardEntry", b =>
|
||||
{
|
||||
b.HasBaseType("DCGEngine.Database.Models.CardEntry");
|
||||
|
||||
b.HasDiscriminator().HasValue("ShadowverseCardEntry");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("DCGEngine.Database.Models.CardEntry", b =>
|
||||
{
|
||||
b.HasOne("SVSim.Database.Models.ShadowverseDeckEntry", null)
|
||||
.WithMany("Cards")
|
||||
.HasForeignKey("ShadowverseDeckEntryId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.SocialAccountConnection", b =>
|
||||
{
|
||||
b.HasOne("SVSim.Database.Models.Viewer", "Viewer")
|
||||
.WithMany()
|
||||
.HasForeignKey("ViewerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Viewer");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SVSim.Database.Models.ShadowverseDeckEntry", b =>
|
||||
{
|
||||
b.Navigation("Cards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
25
SVSim.Database/Models/SocialAccountConnection.cs
Normal file
25
SVSim.Database/Models/SocialAccountConnection.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using DCGEngine.Database.Models;
|
||||
using SVSim.Database.Enums;
|
||||
|
||||
namespace SVSim.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A connection between a social account (ie facebook) and a viewer.
|
||||
/// </summary>
|
||||
public class SocialAccountConnection : BaseEntity<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the social account.
|
||||
/// </summary>
|
||||
public SocialAccountType AccountType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The identifier of the social account.
|
||||
/// </summary>
|
||||
public ulong AccountId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The viewer connected.
|
||||
/// </summary>
|
||||
public Viewer Viewer { get; set; }
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using DCGEngine.Database.Models;
|
||||
|
||||
namespace SVSim.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A user within the game system.
|
||||
/// </summary>
|
||||
public class User : BaseEntity<long>
|
||||
{
|
||||
public string ViewerId { get; set; }
|
||||
public ulong SteamId { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
|
||||
}
|
||||
19
SVSim.Database/Models/Viewer.cs
Normal file
19
SVSim.Database/Models/Viewer.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using DCGEngine.Database.Models;
|
||||
|
||||
namespace SVSim.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A user within the game system.
|
||||
/// </summary>
|
||||
public class Viewer : BaseEntity<ulong>
|
||||
{
|
||||
/// <summary>
|
||||
/// This user's name displayed in game.
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This user's short identifier.
|
||||
/// </summary>
|
||||
public ulong ShortUdid { get; set; }
|
||||
}
|
||||
8
SVSim.Database/Repositories/Viewer/IViewerRepository.cs
Normal file
8
SVSim.Database/Repositories/Viewer/IViewerRepository.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using SVSim.Database.Enums;
|
||||
|
||||
namespace SVSim.Database.Repositories.Viewer;
|
||||
|
||||
public interface IViewerRepository
|
||||
{
|
||||
Task<Models.Viewer?> GetViewerBySocialConnection(SocialAccountType accountType, ulong socialId);
|
||||
}
|
||||
24
SVSim.Database/Repositories/Viewer/ViewerRepository.cs
Normal file
24
SVSim.Database/Repositories/Viewer/ViewerRepository.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
|
||||
namespace SVSim.Database.Repositories.Viewer;
|
||||
|
||||
public class ViewerRepository : IViewerRepository
|
||||
{
|
||||
protected readonly SVSimDbContext _dbContext;
|
||||
|
||||
public ViewerRepository(SVSimDbContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<Models.Viewer?> GetViewerBySocialConnection(SocialAccountType accountType, ulong socialId)
|
||||
{
|
||||
return _dbContext.Set<SocialAccountConnection>()
|
||||
.AsNoTracking()
|
||||
.Include(sac => sac.Viewer)
|
||||
.FirstOrDefault(sac => sac.AccountType == accountType && sac.AccountId == socialId)
|
||||
?.Viewer;
|
||||
}
|
||||
}
|
||||
8
SVSim.EmulatedEntrypoint/Constants/NetworkConstants.cs
Normal file
8
SVSim.EmulatedEntrypoint/Constants/NetworkConstants.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace SVSim.EmulatedEntrypoint.Constants;
|
||||
|
||||
public static class NetworkConstants
|
||||
{
|
||||
public const string UdidHeaderName = "UDID";
|
||||
public const string SessionIdHeaderName = "SID";
|
||||
public const string ShortUdidHeaderName = "SHORT_UDID";
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace SVSim.EmulatedEntrypoint.Constants;
|
||||
|
||||
public static class ShadowverseClaimTypes
|
||||
{
|
||||
public const string ShortUdidClaim = "ShortUdid";
|
||||
public const string ViewerIdClaim = "ViewerId";
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Buffers.Text;
|
||||
using System.Text;
|
||||
using MessagePack;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
@@ -22,6 +23,7 @@ namespace SVSim.EmulatedEntrypoint.Controllers
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("special_title")]
|
||||
public async Task<DataWrapper<SpecialTitleCheckResponse>> SpecialTitleCheck(SpecialTitleCheckRequest request)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SVSim.EmulatedEntrypoint.Security;
|
||||
using SVSim.EmulatedEntrypoint.Security.SteamSessionAuthentication;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Controllers
|
||||
{
|
||||
@@ -9,11 +11,8 @@ namespace SVSim.EmulatedEntrypoint.Controllers
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[Authorize(AuthenticationSchemes = SteamAuthenticationConstants.SchemeName)]
|
||||
public abstract class SVSimController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the UdId of the user making the request. Can be null or empty, as only certain requests will send it. Known requests to send this value are: SignUp, CheckSpecialTitle, CheckiCloudUser, MigrateiCloudUser
|
||||
/// </summary>
|
||||
public string? UdId => Encryption.Decode(Request.Headers["UDID"]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using SVSim.EmulatedEntrypoint.Constants;
|
||||
using SVSim.EmulatedEntrypoint.Security;
|
||||
using SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Middlewares;
|
||||
|
||||
/// <summary>
|
||||
/// Maps an incoming request's session id to a udid if both are present.
|
||||
/// </summary>
|
||||
public class SessionidMappingMiddleware : IMiddleware
|
||||
{
|
||||
private readonly ShadowverseSessionService _shadowverseSessionService;
|
||||
|
||||
public SessionidMappingMiddleware(ShadowverseSessionService shadowverseSessionService)
|
||||
{
|
||||
_shadowverseSessionService = shadowverseSessionService;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
bool hasSessionId = context.Request.Headers.TryGetValue(NetworkConstants.UdidHeaderName, out var udid);
|
||||
bool hasUdid = context.Request.Headers.TryGetValue(NetworkConstants.SessionIdHeaderName, out var sid);
|
||||
if (hasSessionId && hasUdid)
|
||||
{
|
||||
_shadowverseSessionService.StoreUdidForSessionId(sid.FirstOrDefault(), Guid.Parse(Encryption.Decode(udid.FirstOrDefault())));
|
||||
}
|
||||
|
||||
await next.Invoke(context);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,9 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Newtonsoft.Json;
|
||||
using SVSim.EmulatedEntrypoint.Constants;
|
||||
using SVSim.EmulatedEntrypoint.Security;
|
||||
using SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Middlewares;
|
||||
|
||||
@@ -14,10 +16,12 @@ namespace SVSim.EmulatedEntrypoint.Middlewares;
|
||||
public class ShadowverseTranslationMiddleware : IMiddleware
|
||||
{
|
||||
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
|
||||
private readonly ShadowverseSessionService _sessionService;
|
||||
|
||||
public ShadowverseTranslationMiddleware(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider)
|
||||
public ShadowverseTranslationMiddleware(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider, ShadowverseSessionService sessionService)
|
||||
{
|
||||
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
|
||||
_sessionService = sessionService;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
@@ -32,21 +36,33 @@ public class ShadowverseTranslationMiddleware : IMiddleware
|
||||
await next.Invoke(context);
|
||||
return;
|
||||
}
|
||||
using var requestBytesStream = new MemoryStream();
|
||||
|
||||
// Replace response body stream to re-access it.
|
||||
using var tempResponseBody = new MemoryStream();
|
||||
var originalResponsebody = context.Response.Body;
|
||||
context.Response.Body = tempResponseBody;
|
||||
|
||||
// Pull out the request bytes into a stream
|
||||
using var requestBytesStream = new MemoryStream();
|
||||
await context.Request.Body.CopyToAsync(requestBytesStream);
|
||||
byte[] requestBytes = requestBytesStream.ToArray();
|
||||
// Decrypt incoming data. Placeholder.
|
||||
requestBytes = Encryption.Decrypt(requestBytes, Encryption.Decode(context.Request.Headers["UDID"]));
|
||||
|
||||
// Get encryption values for this request
|
||||
string sid = context.Request.Headers[NetworkConstants.SessionIdHeaderName];
|
||||
string udid = _sessionService.GetUdidFromSessionId(sid).GetValueOrDefault().ToString();
|
||||
|
||||
// Decrypt incoming data.
|
||||
requestBytes = Encryption.Decrypt(requestBytes, udid);
|
||||
object? data = MessagePackSerializer.Deserialize(endpointDescriptor.Parameters.FirstOrDefault().ParameterType,
|
||||
requestBytes);
|
||||
var json = JsonConvert.SerializeObject(data);
|
||||
var newStream = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
context.Request.Body = newStream.ReadAsStream();
|
||||
context.Request.Headers.ContentType = new StringValues("application/json");
|
||||
|
||||
await next.Invoke(context);
|
||||
|
||||
// Convert the response into a messagepack, encrypt it
|
||||
var responseType = ((ControllerActionDescriptor)endpointDescriptor).MethodInfo.ReturnType;
|
||||
if (responseType.IsGenericType && responseType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
@@ -58,7 +74,7 @@ public class ShadowverseTranslationMiddleware : IMiddleware
|
||||
var responseBytes = responseBytesStream.ToArray();
|
||||
var responseData = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(responseBytes), responseType);
|
||||
var packedData = MessagePackSerializer.Serialize(responseType, responseData);
|
||||
packedData = Encryption.Encrypt(packedData, Encryption.Decode(context.Request.Headers["UDID"]));
|
||||
packedData = Encryption.Encrypt(packedData, udid);
|
||||
await originalResponsebody.WriteAsync(Encoding.UTF8.GetBytes(Convert.ToBase64String(packedData)));
|
||||
context.Response.Body = originalResponsebody;
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ using MessagePack;
|
||||
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||
|
||||
[MessagePackObject]
|
||||
public abstract class BaseRequest
|
||||
public class BaseRequest
|
||||
{
|
||||
[Key("viewer_id")]
|
||||
public string ViewerId { get; set; }
|
||||
[Key("steam_id")]
|
||||
public long SteamId { get; set; }
|
||||
public ulong SteamId { get; set; }
|
||||
[Key("steam_session_ticket")]
|
||||
public string SteamSessionTicket { get; set; }
|
||||
}
|
||||
@@ -7,8 +7,10 @@ public class TransitionAccountData
|
||||
{
|
||||
[Key("social_account_id")]
|
||||
public string SocialAccountId { get; set; }
|
||||
|
||||
[Key("social_account_type")]
|
||||
public string SocialAccountType { get; set; }
|
||||
|
||||
[Key("connected_viewer_id")]
|
||||
public string ConnectedViewerId { get; set; }
|
||||
}
|
||||
@@ -4,7 +4,10 @@ using DCGEngine.Database.Configuration;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.Database.Repositories.Viewer;
|
||||
using SVSim.EmulatedEntrypoint.Middlewares;
|
||||
using SVSim.EmulatedEntrypoint.Security.SteamSessionAuthentication;
|
||||
using SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint;
|
||||
|
||||
@@ -24,18 +27,42 @@ public class Program
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
#region Database Services
|
||||
|
||||
builder.Services.AddDbContext<SVSimDbContext>(opt =>
|
||||
{
|
||||
opt.UseSqlite();
|
||||
opt.UseSqlite(builder.Configuration.GetConnectionString("Sqlite"));
|
||||
});
|
||||
builder.Services.AddTransient<IViewerRepository, ViewerRepository>();
|
||||
|
||||
#endregion
|
||||
|
||||
builder.Services.AddTransient<ShadowverseTranslationMiddleware>();
|
||||
builder.Services.AddTransient<SessionidMappingMiddleware>();
|
||||
builder.Services.Configure<DCGEDatabaseConfiguration>(opt =>
|
||||
{
|
||||
opt.DbSetSearchAssemblies = new List<Assembly> { Assembly.GetAssembly(typeof(SVSimDbContext)) };
|
||||
});
|
||||
builder.Services.AddSingleton<ShadowverseSessionService>();
|
||||
builder.Services.AddSingleton<SteamSessionService>();
|
||||
builder.Services.AddAuthentication()
|
||||
.AddScheme<SteamAuthenticationHandlerOptions, SteamSessionAuthenticationHandler>(
|
||||
SteamAuthenticationConstants.SchemeName,
|
||||
opt =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Update database
|
||||
using (var scope = app.Services.CreateScope())
|
||||
{
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
dbContext.UpdateDatabase();
|
||||
}
|
||||
|
||||
app.UseHttpLogging();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
@@ -47,8 +74,12 @@ public class Program
|
||||
|
||||
//app.UseHttpsRedirection();
|
||||
|
||||
app.UseMiddleware<SessionidMappingMiddleware>();
|
||||
|
||||
app.UseMiddleware<ShadowverseTranslationMiddleware>();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
|
||||
|
||||
@@ -32,4 +32,29 @@
|
||||
<ProjectReference Include="..\SVSim.Database\SVSim.Database.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="lib\libsteam_api.so">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="lib\libsteam_api.so.meta">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="lib\steam_api.dll">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="lib\steam_api.lib">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="lib\steam_api64.dll">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="lib\steam_api64.lib">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="COPY "$(ProjectDir)\lib\*" "$(TargetDir)"" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -58,27 +58,29 @@ public static class Encryption
|
||||
/// <returns>the decrypted bytes</returns>
|
||||
public static byte[] Decrypt(byte[] encryptedData, string udId)
|
||||
{
|
||||
using (var rj = Aes.Create())
|
||||
using (var rj = new RijndaelManaged())
|
||||
{
|
||||
rj.KeySize = EncryptionKeySize;
|
||||
rj.Mode = EncryptionMode;
|
||||
rj.BlockSize = EncryptionBlockSize;
|
||||
//rj.Padding = PaddingMode.None;
|
||||
byte[] rgbIv = Encoding.UTF8.GetBytes(udId.Replace("-", string.Empty).Substring(0, UdIdKeySize));
|
||||
byte[] keyBytes = new byte[KeyStringSize];
|
||||
byte[] encryptedValueBytes = new byte[encryptedData.Length - KeyStringSize];
|
||||
Array.Copy(encryptedData, encryptedData.Length - keyBytes.Length, keyBytes, 0, keyBytes.Length);
|
||||
Array.Copy(encryptedData, 0, encryptedValueBytes, 0, encryptedValueBytes.Length);
|
||||
ICryptoTransform transform = rj.CreateDecryptor(keyBytes, rgbIv);
|
||||
byte[] decryptedValueBytes = new byte[encryptedValueBytes.Length];
|
||||
using (MemoryStream ms = new MemoryStream(encryptedValueBytes))
|
||||
{
|
||||
using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
|
||||
{
|
||||
byte[] decryptedValueBytes = new byte[encryptedValueBytes.Length];
|
||||
cs.Read(decryptedValueBytes, 0, encryptedValueBytes.Length);
|
||||
cs.FlushFinalBlock();
|
||||
return decryptedValueBytes;
|
||||
cs.CopyTo(decryptedValueBytes);
|
||||
cs.Flush();
|
||||
ms.Flush();
|
||||
}
|
||||
}
|
||||
return decryptedValueBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace SVSim.EmulatedEntrypoint.Security.SteamSessionAuthentication;
|
||||
|
||||
public static class SteamAuthenticationConstants
|
||||
{
|
||||
public const string SchemeName = "SteamAuthentication";
|
||||
public const string SteamIdClaim = "SteamId";
|
||||
}
|
||||
@@ -1,21 +1,74 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
using SVSim.Database.Repositories.Viewer;
|
||||
using SVSim.EmulatedEntrypoint.Constants;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||
using SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Security.SteamSessionAuthentication;
|
||||
|
||||
public class SteamSessionAuthenticationHandler : AuthenticationHandler<SteamAuthenticationHandlerOptions>
|
||||
{
|
||||
public SteamSessionAuthenticationHandler(IOptionsMonitor<SteamAuthenticationHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
public SteamSessionAuthenticationHandler(IOptionsMonitor<SteamAuthenticationHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder)
|
||||
private readonly SteamSessionService _sessionService;
|
||||
private readonly IViewerRepository _viewerRepository;
|
||||
public SteamSessionAuthenticationHandler(IOptionsMonitor<SteamAuthenticationHandlerOptions> options, ILoggerFactory logger, UrlEncoder encoder, SteamSessionService sessionService, IViewerRepository viewerRepository) : base(options, logger, encoder)
|
||||
{
|
||||
_sessionService = sessionService;
|
||||
_viewerRepository = viewerRepository;
|
||||
}
|
||||
|
||||
protected async override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
return AuthenticateResult.Fail("Not implemented");
|
||||
byte[] requestBytes;
|
||||
using (var requestBytesStream = new MemoryStream())
|
||||
{
|
||||
await Request.Body.CopyToAsync(requestBytesStream);
|
||||
requestBytes = requestBytesStream.ToArray();
|
||||
}
|
||||
|
||||
// Convert bytes to json
|
||||
string requestString = Encoding.UTF8.GetString(requestBytes);
|
||||
BaseRequest? requestJson = JsonConvert.DeserializeObject<BaseRequest>(requestString);
|
||||
|
||||
// Reset request stream
|
||||
Request.Body.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (requestJson is null)
|
||||
{
|
||||
return AuthenticateResult.Fail("Invalid request body.");
|
||||
}
|
||||
|
||||
// Check steam session validity
|
||||
bool sessionIsValid = _sessionService.IsTicketValidForUser(requestJson.SteamSessionTicket, requestJson.SteamId);
|
||||
if (!sessionIsValid)
|
||||
{
|
||||
return AuthenticateResult.Fail("Invalid ticket.");
|
||||
}
|
||||
|
||||
Viewer? viewer =
|
||||
await _viewerRepository.GetViewerBySocialConnection(SocialAccountType.Steam, requestJson.SteamId);
|
||||
|
||||
if (viewer is null)
|
||||
{
|
||||
return AuthenticateResult.Fail("User not found.");
|
||||
}
|
||||
|
||||
// Build identity
|
||||
ClaimsIdentity identity = new ClaimsIdentity();
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, viewer.DisplayName));
|
||||
identity.AddClaim(new Claim(ShadowverseClaimTypes.ShortUdidClaim, viewer.ShortUdid.ToString()));
|
||||
identity.AddClaim(new Claim(ShadowverseClaimTypes.ViewerIdClaim, viewer.Id.ToString()));
|
||||
identity.AddClaim(new Claim(SteamAuthenticationConstants.SteamIdClaim, requestJson.SteamId.ToString()));
|
||||
|
||||
// Build and return final ticket
|
||||
AuthenticationTicket ticket =
|
||||
new AuthenticationTicket(new ClaimsPrincipal(), SteamAuthenticationConstants.SchemeName);
|
||||
return AuthenticateResult.Success(ticket);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Services;
|
||||
|
||||
public class ShadowverseSessionService
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Guid> _sessionIdToUdid;
|
||||
|
||||
public ShadowverseSessionService()
|
||||
{
|
||||
_sessionIdToUdid = new();
|
||||
}
|
||||
|
||||
public Guid? GetUdidFromSessionId(string sid)
|
||||
{
|
||||
if (_sessionIdToUdid.TryGetValue(sid, out var udid))
|
||||
{
|
||||
return udid;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void StoreUdidForSessionId(string sid, Guid udid)
|
||||
{
|
||||
_sessionIdToUdid.AddOrUpdate(sid, _ => udid, (_, _) => udid);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
namespace SVSim.EmulatedEntrypoint;
|
||||
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
@@ -6,5 +6,8 @@
|
||||
"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Sqlite": "Data Source=test_db"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
BIN
SVSim.EmulatedEntrypoint/lib/libsteam_api.so
Normal file
BIN
SVSim.EmulatedEntrypoint/lib/libsteam_api.so
Normal file
Binary file not shown.
Binary file not shown.
BIN
SVSim.EmulatedEntrypoint/lib/steam_api.lib
Normal file
BIN
SVSim.EmulatedEntrypoint/lib/steam_api.lib
Normal file
Binary file not shown.
Binary file not shown.
BIN
SVSim.EmulatedEntrypoint/lib/steam_api64.lib
Normal file
BIN
SVSim.EmulatedEntrypoint/lib/steam_api64.lib
Normal file
Binary file not shown.
@@ -16,6 +16,6 @@ public class Tests
|
||||
"140000005ee7d30c1263e214e133a10001001001e07cd866180000000100000002000000b8526bb7b8946cd27c214574f1000000b20000003200000004000000e133a1000100100168eb0600488cc2443101a8c0000000008165d4660115f06601005c7e010000000000cad61456a2b83d39595c3e3749b96b4537ebde88d048103a6f6c7b2b81ee68711378836872a11422f5bd16fad803f81122c5ae98d986b693bbbc00ac7d30a8f85af2c1a7dce57751eb2c7f21130284aa8d9ee787246c8ccc138f05936bacb1ba4baba5fa5fbf6158002cf7207ae25a6f6ee8e3fc8edbb84903d346a249179637";
|
||||
using var steamService = new SteamSessionService();
|
||||
bool validTicket = steamService.IsTicketValidForUser(ticket, 76561197970830305);
|
||||
Assert.AreEqual(true, validTicket);
|
||||
Assert.That(validTicket, Is.EqualTo(true));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user