Moved database-related logic to own project
Moved tests into their own respective project-folder Moved most composition logic to their own respective project Moved Cobra.Hook to its own solution Added almost all database models based on existing ERD Added tests for SteamAuthMiddleware Added UserService to retrieve the user associated with the current request Added HitmanUserService to perform user-specific actions on the database Added start of actual multi-user HitmanServer implemention Cleaned up SteamAuthMiddleware based on tests
This commit is contained in:
parent
dedb008c81
commit
107edbea8a
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="LocalDatabase.db" uuid="e5c25f83-a441-487d-9e27-a6bb95bfddcc">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/Src/Cobra.Server/Data/LocalDatabase.db</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.4.33122.133
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentation", "{43E1351B-28D0-45FE-A10A-545CFE650039}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.gitignore = .gitignore
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cobra.Hook", "Src\Cobra.Hook\Cobra.Hook.vcxproj", "{57ABB826-E2F3-4908-BBBB-634C1A747CAA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.Build.0 = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.ActiveCfg = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.Build.0 = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {742A6A34-A300-4A5A-BD85-0CBCC7421E7A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
31
Cobra.sln
31
Cobra.sln
|
@ -12,8 +12,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Documentation", "Documentat
|
|||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Cobra.Hook", "Src\Cobra.Hook\Cobra.Hook.vcxproj", "{57ABB826-E2F3-4908-BBBB-634C1A747CAA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cobra.Test", "Src\Cobra.Test\Cobra.Test.csproj", "{815C296D-7137-4DC6-96FF-4EC7432CEA1F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cobra.Analyzer", "Src\Cobra.Analyzer\Cobra.Analyzer.csproj", "{EC31FDCB-1EF1-4B39-8404-5E3BAF26A3D2}"
|
||||
|
@ -28,7 +26,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D1082260
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cobra.Server.Sniper", "Src\Cobra.Server.Sniper\Cobra.Server.Sniper.csproj", "{9D3CA9E4-4C90-46F6-9638-1A51380ACEAF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cobra.Server.Hitman", "Src\Cobra.Server.Hitman\Cobra.Server.Hitman.csproj", "{32FEBCBD-2000-4097-A01D-A9423C920354}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cobra.Server.Hitman", "Src\Cobra.Server.Hitman\Cobra.Server.Hitman.csproj", "{32FEBCBD-2000-4097-A01D-A9423C920354}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cobra.Server.Database", "Src\Cobra.Server.Database\Cobra.Server.Database.csproj", "{0AC11ABA-A1C0-4027-A19F-485F17DE6580}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -52,18 +52,6 @@ Global
|
|||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6FA95780-4890-46C7-9342-C5CC7E465EEF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x64.Build.0 = Debug|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.ActiveCfg = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x64.Build.0 = Release|x64
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA}.Release|x86.Build.0 = Release|Win32
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
|
@ -136,12 +124,23 @@ Global
|
|||
{32FEBCBD-2000-4097-A01D-A9423C920354}.Release|x64.Build.0 = Release|Any CPU
|
||||
{32FEBCBD-2000-4097-A01D-A9423C920354}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{32FEBCBD-2000-4097-A01D-A9423C920354}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0AC11ABA-A1C0-4027-A19F-485F17DE6580}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{57ABB826-E2F3-4908-BBBB-634C1A747CAA} = {ADCBE1D4-26D9-48A0-87A1-4BA6D851C9F5}
|
||||
{815C296D-7137-4DC6-96FF-4EC7432CEA1F} = {D1082260-6FB2-4A86-B8D3-E4B75DC7A3B3}
|
||||
{EC31FDCB-1EF1-4B39-8404-5E3BAF26A3D2} = {ADCBE1D4-26D9-48A0-87A1-4BA6D851C9F5}
|
||||
EndGlobalSection
|
||||
|
|
|
@ -23,6 +23,11 @@
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=leaderboardtype/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=levelindex/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=metacategories/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=OSAUTHPROVIDER/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=OSAUTHRESPONSE/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=OSAUTHTICKETDATA/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=OSERROR/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=OSUID/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Silverballer/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Splitted/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=startindex/@EntryIndexedValue">True</s:Boolean>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# Development
|
||||
This document described how to get started with the project.
|
||||
|
||||
# Add database migration to project
|
||||
Run the following command from the `Src\Cobra.Server` folder:
|
||||
```
|
||||
dotnet ef migrations add [Name] --project ../Cobra.Server.Database
|
||||
```
|
||||
|
||||
Where `[Name]` is replace with the name of the migration you wish to add.
|
||||
|
||||
# Apply database migration to database
|
||||
Run the following command from the `Src\Cobra.Server` folder:
|
||||
```
|
||||
dotnet ef database update --project ../Cobra.Server.Database
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.12" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Cobra.Analyzer\Cobra.Analyzer.csproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Cobra.Server.Shared\Cobra.Server.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,28 @@
|
|||
using Cobra.Server.Shared.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Cobra.Server.Database
|
||||
{
|
||||
public static class Compositions
|
||||
{
|
||||
public static void ConfigureServices(IServiceCollection services, IConfiguration configuration, Options options)
|
||||
{
|
||||
services.AddDbContextFactory<DatabaseContext>(optionsBuilder =>
|
||||
{
|
||||
optionsBuilder
|
||||
.UseSqlite(
|
||||
configuration.GetConnectionString("CobraDatabase"),
|
||||
x => x.MigrationsAssembly("Cobra.Server.Database")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Configure(IServiceProvider services)
|
||||
{
|
||||
var databaseContext = services.GetRequiredService<DatabaseContext>();
|
||||
databaseContext.Database.Migrate();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using Cobra.Server.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database
|
||||
{
|
||||
public class DatabaseContext : DbContext
|
||||
{
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<UserFriend> UserFriends { get; set; }
|
||||
public DbSet<UserContract> UserContracts { get; set; }
|
||||
public DbSet<Contract> Contracts { get; set; }
|
||||
public DbSet<ContractTarget> ContractTargets { get; set; }
|
||||
public DbSet<ScoreStory> ScoresStory { get; set; }
|
||||
public DbSet<ScoreSniper> ScoresSniper { get; set; }
|
||||
public DbSet<ScoreTutorial> ScoresTutorial { get; set; }
|
||||
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> dbContextOptions)
|
||||
: base(dbContextOptions)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace Cobra.Server.Database.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum EContractRestrictionType : byte
|
||||
{
|
||||
None = 0,
|
||||
TargetOnly = 1,
|
||||
SuitOnly = 2,
|
||||
PerfectShooter = 4,
|
||||
EraseTraces = 8,
|
||||
NoWitnesses = 16
|
||||
}
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Cobra.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20231026172304_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.12");
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.Contract", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CheckpointIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ExitId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LevelIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("OutfitToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<byte>("Restrictions")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Target1Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint?>("Target2Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint?>("Target3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WeaponToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Target1Id");
|
||||
|
||||
b.HasIndex("Target2Id");
|
||||
|
||||
b.HasIndex("Target3Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Contracts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ContractTarget", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AmmoType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("OutfitToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SpecialSituation")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WeaponToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name", "WeaponToken", "OutfitToken", "AmmoType", "SpecialSituation")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ContractTargets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreSniper", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("ScoresSniper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreStory", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ScoresStory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreTutorial", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("ScoresTutorial");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CompetitionPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ContractPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Country")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Trophies")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Wallet")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Country");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserContract", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ContractId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastPlayedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool?>("Liked")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Plays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Queued")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "ContractId");
|
||||
|
||||
b.HasIndex("ContractId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "Queued");
|
||||
|
||||
b.ToTable("UserContracts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserFriend", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("SteamId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "SteamId");
|
||||
|
||||
b.ToTable("UserFriends");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.Contract", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target1")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target1Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target2")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target2Id");
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target3")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target3Id");
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Target1");
|
||||
|
||||
b.Navigation("Target2");
|
||||
|
||||
b.Navigation("Target3");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreSniper", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreStory", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreTutorial", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserContract", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.Contract", "Contract")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContractId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Contract");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserFriend", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany("Friends")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Friends");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ContractTargets",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<uint>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||
WeaponToken = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
OutfitToken = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
AmmoType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
SpecialSituation = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ContractTargets", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DisplayName = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Country = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Wallet = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ContractPlays = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CompetitionPlays = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Trophies = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Contracts",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
DisplayId = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Title = table.Column<string>(type: "TEXT", nullable: false),
|
||||
Description = table.Column<string>(type: "TEXT", nullable: false),
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
LevelIndex = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CheckpointIndex = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Difficulty = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ExitId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
WeaponToken = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
OutfitToken = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Target1Id = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
Target2Id = table.Column<uint>(type: "INTEGER", nullable: true),
|
||||
Target3Id = table.Column<uint>(type: "INTEGER", nullable: true),
|
||||
Restrictions = table.Column<byte>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Contracts", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Contracts_ContractTargets_Target1Id",
|
||||
column: x => x.Target1Id,
|
||||
principalTable: "ContractTargets",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_Contracts_ContractTargets_Target2Id",
|
||||
column: x => x.Target2Id,
|
||||
principalTable: "ContractTargets",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Contracts_ContractTargets_Target3Id",
|
||||
column: x => x.Target3Id,
|
||||
principalTable: "ContractTargets",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Contracts_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ScoresSniper",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Score = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ScoresSniper", x => x.UserId);
|
||||
table.ForeignKey(
|
||||
name: "FK_ScoresSniper_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ScoresStory",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Score = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ScoresStory", x => new { x.Id, x.UserId });
|
||||
table.ForeignKey(
|
||||
name: "FK_ScoresStory_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ScoresTutorial",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Score = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ScoresTutorial", x => x.UserId);
|
||||
table.ForeignKey(
|
||||
name: "FK_ScoresTutorial_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "UserFriends",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
SteamId = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_UserFriends", x => new { x.UserId, x.SteamId });
|
||||
table.ForeignKey(
|
||||
name: "FK_UserFriends_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "UserContracts",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ContractId = table.Column<uint>(type: "INTEGER", nullable: false),
|
||||
Queued = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
Plays = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Score = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Liked = table.Column<bool>(type: "INTEGER", nullable: true),
|
||||
LastPlayedAt = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_UserContracts", x => new { x.UserId, x.ContractId });
|
||||
table.ForeignKey(
|
||||
name: "FK_UserContracts_Contracts_ContractId",
|
||||
column: x => x.ContractId,
|
||||
principalTable: "Contracts",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_UserContracts_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_DisplayId",
|
||||
table: "Contracts",
|
||||
column: "DisplayId",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_Target1Id",
|
||||
table: "Contracts",
|
||||
column: "Target1Id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_Target2Id",
|
||||
table: "Contracts",
|
||||
column: "Target2Id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_Target3Id",
|
||||
table: "Contracts",
|
||||
column: "Target3Id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Contracts_UserId",
|
||||
table: "Contracts",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ContractTargets_Name_WeaponToken_OutfitToken_AmmoType_SpecialSituation",
|
||||
table: "ContractTargets",
|
||||
columns: new[] { "Name", "WeaponToken", "OutfitToken", "AmmoType", "SpecialSituation" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ScoresStory_UserId",
|
||||
table: "ScoresStory",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserContracts_ContractId",
|
||||
table: "UserContracts",
|
||||
column: "ContractId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserContracts_UserId",
|
||||
table: "UserContracts",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserContracts_UserId_Queued",
|
||||
table: "UserContracts",
|
||||
columns: new[] { "UserId", "Queued" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Users_Country",
|
||||
table: "Users",
|
||||
column: "Country");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ScoresSniper");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ScoresStory");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ScoresTutorial");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "UserContracts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "UserFriends");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Contracts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ContractTargets");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Cobra.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
partial class DatabaseContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.12");
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.Contract", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CheckpointIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Difficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ExitId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("LevelIndex")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("OutfitToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<byte>("Restrictions")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("Target1Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint?>("Target2Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint?>("Target3Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WeaponToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DisplayId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Target1Id");
|
||||
|
||||
b.HasIndex("Target2Id");
|
||||
|
||||
b.HasIndex("Target3Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Contracts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ContractTarget", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AmmoType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("OutfitToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SpecialSituation")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("WeaponToken")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name", "WeaponToken", "OutfitToken", "AmmoType", "SpecialSituation")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ContractTargets");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreSniper", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("ScoresSniper");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreStory", b =>
|
||||
{
|
||||
b.Property<uint>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id", "UserId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ScoresStory");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreTutorial", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("ScoresTutorial");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CompetitionPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ContractPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Country")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Trophies")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Wallet")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Country");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserContract", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ContractId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastPlayedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool?>("Liked")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Plays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("Queued")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Score")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "ContractId");
|
||||
|
||||
b.HasIndex("ContractId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.HasIndex("UserId", "Queued");
|
||||
|
||||
b.ToTable("UserContracts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserFriend", b =>
|
||||
{
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("SteamId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("UserId", "SteamId");
|
||||
|
||||
b.ToTable("UserFriends");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.Contract", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target1")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target1Id")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target2")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target2Id");
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.ContractTarget", "Target3")
|
||||
.WithMany()
|
||||
.HasForeignKey("Target3Id");
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Target1");
|
||||
|
||||
b.Navigation("Target2");
|
||||
|
||||
b.Navigation("Target3");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreSniper", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreStory", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.ScoreTutorial", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserContract", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.Contract", "Contract")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContractId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Contract");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.UserFriend", b =>
|
||||
{
|
||||
b.HasOne("Cobra.Server.Database.Models.User", "User")
|
||||
.WithMany("Friends")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Navigation("Friends");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Cobra.Server.Database.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[Index(nameof(DisplayId), IsUnique = true)]
|
||||
public class Contract
|
||||
{
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string DisplayId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Title { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Required]
|
||||
public User User { get; set; }
|
||||
|
||||
public int LevelIndex { get; set; }
|
||||
public int CheckpointIndex { get; set; }
|
||||
public int Difficulty { get; set; }
|
||||
public int ExitId { get; set; }
|
||||
public int WeaponToken { get; set; }
|
||||
public int OutfitToken { get; set; }
|
||||
|
||||
[Required]
|
||||
public ContractTarget Target1 { get; set; }
|
||||
|
||||
public ContractTarget Target2 { get; set; }
|
||||
public ContractTarget Target3 { get; set; }
|
||||
public EContractRestrictionType Restrictions { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[Index(
|
||||
nameof(Name),
|
||||
nameof(WeaponToken), nameof(OutfitToken), nameof(AmmoType), nameof(SpecialSituation),
|
||||
IsUnique = true
|
||||
)]
|
||||
public class ContractTarget
|
||||
{
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public uint Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
public int WeaponToken { get; set; }
|
||||
public int OutfitToken { get; set; }
|
||||
public int AmmoType { get; set; }
|
||||
public int SpecialSituation { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
public class ScoreSniper
|
||||
{
|
||||
[Key, ForeignKey(nameof(User))]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
public int Score { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[PrimaryKey(nameof(Id), nameof(UserId))]
|
||||
public class ScoreStory
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public uint Id { get; set; } //NOTE: Leaderboard ID
|
||||
|
||||
[ForeignKey(nameof(User))]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
public int Score { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
public class ScoreTutorial
|
||||
{
|
||||
[Key, ForeignKey(nameof(User))]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
public int Score { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,19 +1,24 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[Index(nameof(Country))]
|
||||
public class User
|
||||
{
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public ulong Id { get; set; }
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public ulong Id { get; set; } //NOTE: SteamId
|
||||
|
||||
public ulong SteamId { get; set; }
|
||||
[Required]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
public int Country { get; set; }
|
||||
public int Wallet { get; set; }
|
||||
public int ContractPlays { get; set; }
|
||||
public int CompetitionPlays { get; set; }
|
||||
public int Trophies { get; set; }
|
||||
|
||||
public ICollection<UserFriend> Friends { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[PrimaryKey(nameof(UserId), nameof(ContractId))]
|
||||
[Index(nameof(UserId))]
|
||||
[Index(nameof(UserId), nameof(Queued))]
|
||||
public class UserContract
|
||||
{
|
||||
[ForeignKey(nameof(User))]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
[ForeignKey(nameof(Contract))]
|
||||
public uint ContractId { get; set; }
|
||||
|
||||
public bool Queued { get; set; }
|
||||
public int? Plays { get; set; }
|
||||
public int? Score { get; set; }
|
||||
public bool? Liked { get; set; }
|
||||
public DateTime? LastPlayedAt { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
public Contract Contract { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database.Models
|
||||
{
|
||||
[PrimaryKey(nameof(UserId), nameof(SteamId))]
|
||||
public class UserFriend
|
||||
{
|
||||
[ForeignKey(nameof(User))]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public ulong SteamId { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Cobra.Server.Database\Cobra.Server.Database.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Shared\Cobra.Server.Shared.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Edm\Cobra.Server.Edm.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
using Cobra.Server.Hitman.Interfaces;
|
||||
using Cobra.Server.Hitman.Services;
|
||||
using Cobra.Server.Shared.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Cobra.Server.Hitman
|
||||
{
|
||||
public static class Compositions
|
||||
{
|
||||
public static void ConfigureServices(IServiceCollection services, IConfiguration configuration, Options options)
|
||||
{
|
||||
services.AddSingleton<IHitmanMetadataService, HitmanMetadataService>();
|
||||
|
||||
switch (options.GameService)
|
||||
{
|
||||
case Options.EGameService.Mocked:
|
||||
services.AddSingleton<IHitmanServer, MockedHitmanServer>();
|
||||
break;
|
||||
|
||||
case Options.EGameService.Local:
|
||||
services.AddSingleton<IHitmanServer, LocalHitmanServer>();
|
||||
services.AddSingleton<IContractsService, LocalContractsService>();
|
||||
break;
|
||||
|
||||
case Options.EGameService.Public:
|
||||
services.AddSingleton<IHitmanServer, HitmanServer>();
|
||||
services.AddSingleton<IHitmanUserService, HitmanUserService>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Configure(IServiceProvider services)
|
||||
{
|
||||
var hitmanServer = services.GetRequiredService<IHitmanServer>();
|
||||
hitmanServer.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,9 +26,9 @@ namespace Cobra.Server.Hitman.Controllers
|
|||
|
||||
[HttpGet]
|
||||
[Route("GetUserOverviewData")]
|
||||
public IActionResult GetUserOverviewData([FromQuery] GetUserOverviewDataRequest request)
|
||||
public async Task<IActionResult> GetUserOverviewData([FromQuery] GetUserOverviewDataRequest request)
|
||||
{
|
||||
return JsonEntryResponse(_hitmanServer.GetUserOverviewData(request));
|
||||
return JsonEntryResponse(await _hitmanServer.GetUserOverviewData(request));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Cobra.Server.Hitman.Interfaces
|
|||
Contract GetFeaturedContract(GetFeaturedContractRequest request);
|
||||
List<Message> GetMessages(GetMessagesRequest request);
|
||||
int GetNewMessageCount(GetNewMessageCountRequest request);
|
||||
GetUserOverviewData GetUserOverviewData(GetUserOverviewDataRequest request);
|
||||
int GetUserWallet(GetUserWalletRequest request);
|
||||
Task<GetUserOverviewData> GetUserOverviewData(GetUserOverviewDataRequest request);
|
||||
Task<int> GetUserWallet(GetUserWalletRequest request);
|
||||
void InviteToCompetition(InviteToCompetitionRequest request);
|
||||
void MarkContractAsPlayed(MarkContractAsPlayedRequest request);
|
||||
//MergeUserTokens
|
||||
|
@ -29,7 +29,7 @@ namespace Cobra.Server.Hitman.Interfaces
|
|||
void SetMessageReadStatus(SetMessageReadStatusRequest request);
|
||||
void UpdateContractLikeDislikes(UpdateContractLikeDislikesRequest request);
|
||||
//UpdateDLCInfo
|
||||
void UpdateUserInfo(UpdateUserInfoRequest request);
|
||||
Task UpdateUserInfo(UpdateUserInfoRequest request);
|
||||
//UpdateUserProfileChallenges
|
||||
//UpdateUserProfileGameStats
|
||||
//UpdateUserProfileLevelProgression
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using Cobra.Server.Hitman.Models;
|
||||
|
||||
namespace Cobra.Server.Hitman.Interfaces
|
||||
{
|
||||
public interface IHitmanUserService
|
||||
{
|
||||
Task<GetUserOverviewData> GetUserOverviewData(ulong userId);
|
||||
Task<int?> GetUserWallet(ulong userId);
|
||||
Task UpdateUserInfo(ulong userId, string displayName, int country, List<ulong> friends);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
using Cobra.Server.Hitman.Controllers;
|
||||
using Cobra.Server.Hitman.Interfaces;
|
||||
using Cobra.Server.Hitman.Models;
|
||||
using Cobra.Server.Shared.Interfaces;
|
||||
|
||||
namespace Cobra.Server.Hitman.Services
|
||||
{
|
||||
public class HitmanServer : IHitmanServer
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly IHitmanUserService _hitmanUserService;
|
||||
|
||||
public HitmanServer(
|
||||
IUserService userService,
|
||||
IHitmanUserService hitmanUserService
|
||||
)
|
||||
{
|
||||
_userService = userService;
|
||||
_hitmanUserService = hitmanUserService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void CreateCompetition(HitmanController.CreateCompetitionRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public int ExecuteWalletTransaction(HitmanController.ExecuteWalletTransactionRequest request)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<int> GetAverageScores(HitmanController.BaseGetAverageScoresRequest request)
|
||||
{
|
||||
return new List<int> { 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
public List<ScoreEntry> GetScores(HitmanController.BaseGetScoresRequest request)
|
||||
{
|
||||
return new List<ScoreEntry>();
|
||||
}
|
||||
|
||||
public ScoreComparison GetScoreComparison(HitmanController.GetScoreComparisonRequest request)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Contract GetFeaturedContract(HitmanController.GetFeaturedContractRequest request)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Message> GetMessages(HitmanController.GetMessagesRequest request)
|
||||
{
|
||||
return new List<Message>();
|
||||
}
|
||||
|
||||
public int GetNewMessageCount(HitmanController.GetNewMessageCountRequest request)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public async Task<GetUserOverviewData> GetUserOverviewData(HitmanController.GetUserOverviewDataRequest request)
|
||||
{
|
||||
var userId = _userService.GetCurrentUserId();
|
||||
|
||||
return await _hitmanUserService.GetUserOverviewData(userId);
|
||||
}
|
||||
|
||||
public async Task<int> GetUserWallet(HitmanController.GetUserWalletRequest request)
|
||||
{
|
||||
var userId = _userService.GetCurrentUserId();
|
||||
|
||||
return await _hitmanUserService.GetUserWallet(userId) ?? 0;
|
||||
}
|
||||
|
||||
public void InviteToCompetition(HitmanController.InviteToCompetitionRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void MarkContractAsPlayed(HitmanController.MarkContractAsPlayedRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public int PutScore(HitmanController.PutScoreRequest request)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void QueueAddContract(HitmanController.QueueAddContractRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void QueueRemoveContract(HitmanController.QueueRemoveContractRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void ReportContract(HitmanController.ReportContractRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public List<Contract> SearchForContracts2(HitmanController.SearchForContracts2Request request)
|
||||
{
|
||||
return new List<Contract>();
|
||||
}
|
||||
|
||||
public void SendTemplatedMessage(HitmanController.SendTemplatedMessageRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void SetMessageReadStatus(HitmanController.SetMessageReadStatusRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public void UpdateContractLikeDislikes(HitmanController.UpdateContractLikeDislikesRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
public Task UpdateUserInfo(HitmanController.UpdateUserInfoRequest request)
|
||||
{
|
||||
var userId = _userService.GetCurrentUserId();
|
||||
|
||||
var friends = request.Friends
|
||||
.Select(ulong.Parse)
|
||||
.ToList();
|
||||
|
||||
//TODO: Validate if country is a valid id, this is a non-standard and will have to be extracted from the game.
|
||||
|
||||
_hitmanUserService.UpdateUserInfo(
|
||||
userId,
|
||||
request.DisplayName,
|
||||
request.Country,
|
||||
friends
|
||||
);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void UploadContract(HitmanController.UploadContractRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using Cobra.Server.Database;
|
||||
using Cobra.Server.Database.Models;
|
||||
using Cobra.Server.Hitman.Interfaces;
|
||||
using Cobra.Server.Hitman.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Hitman.Services
|
||||
{
|
||||
public class HitmanUserService : IHitmanUserService
|
||||
{
|
||||
private readonly IDbContextFactory<DatabaseContext> _databaseContextFactory;
|
||||
|
||||
public HitmanUserService(IDbContextFactory<DatabaseContext> databaseContextFactory)
|
||||
{
|
||||
_databaseContextFactory = databaseContextFactory;
|
||||
}
|
||||
|
||||
public async Task<GetUserOverviewData> GetUserOverviewData(ulong userId)
|
||||
{
|
||||
await using var databaseContext = await _databaseContextFactory.CreateDbContextAsync();
|
||||
|
||||
var user = await databaseContext.Users.FindAsync(userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO: Perform a specific (agnostic) query to satisfy as much data as possible
|
||||
return new GetUserOverviewData
|
||||
{
|
||||
WalletAmount = user.Wallet,
|
||||
ContractPlays = user.ContractPlays,
|
||||
CompetitionPlays = user.CompetitionPlays,
|
||||
TrophiesEarned = user.Trophies
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<int?> GetUserWallet(ulong userId)
|
||||
{
|
||||
await using var databaseContext = await _databaseContextFactory.CreateDbContextAsync();
|
||||
|
||||
var user = await databaseContext.Users.FindAsync(userId);
|
||||
|
||||
return user?.Wallet;
|
||||
}
|
||||
|
||||
public async Task UpdateUserInfo(ulong userId, string displayName, int country, List<ulong> friends)
|
||||
{
|
||||
await using var databaseContext = await _databaseContextFactory.CreateDbContextAsync();
|
||||
|
||||
var user = await databaseContext.Users
|
||||
.Include(x => x.Friends)
|
||||
.FirstOrDefaultAsync(x => x.Id == userId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = new User
|
||||
{
|
||||
Id = userId
|
||||
};
|
||||
|
||||
databaseContext.Users.Add(user);
|
||||
}
|
||||
|
||||
user.DisplayName = displayName;
|
||||
user.Country = country;
|
||||
|
||||
//NOTE: This will effectively drop old friends and add new ones
|
||||
user.Friends = friends.Select(x => new UserFriend
|
||||
{
|
||||
User = user,
|
||||
SteamId = x
|
||||
}).ToList();
|
||||
|
||||
await databaseContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ using Microsoft.AspNetCore.WebUtilities;
|
|||
|
||||
namespace Cobra.Server.Hitman.Services
|
||||
{
|
||||
public class ContractsService : IContractsService
|
||||
public class LocalContractsService : IContractsService
|
||||
{
|
||||
public class SimpleContract
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ namespace Cobra.Server.Hitman.Services
|
|||
|
||||
private readonly ConcurrentDictionary<string, Contract> _contractCache;
|
||||
|
||||
public ContractsService()
|
||||
public LocalContractsService()
|
||||
{
|
||||
_contractCache = new ConcurrentDictionary<string, Contract>();
|
||||
}
|
|
@ -52,7 +52,10 @@ namespace Cobra.Server.Hitman.Services
|
|||
|
||||
private UserProfile _userProfile;
|
||||
|
||||
public LocalHitmanServer(ISimpleLogger logger, IContractsService contractsService)
|
||||
public LocalHitmanServer(
|
||||
ISimpleLogger logger,
|
||||
IContractsService contractsService
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_contractsService = contractsService;
|
||||
|
@ -124,19 +127,19 @@ namespace Cobra.Server.Hitman.Services
|
|||
return 0;
|
||||
}
|
||||
|
||||
public GetUserOverviewData GetUserOverviewData(GetUserOverviewDataRequest request)
|
||||
public Task<GetUserOverviewData> GetUserOverviewData(GetUserOverviewDataRequest request)
|
||||
{
|
||||
return new GetUserOverviewData
|
||||
return Task.FromResult(new GetUserOverviewData
|
||||
{
|
||||
WalletAmount = _userProfile.TotalEarnings,
|
||||
ContractPlays = _userProfile.PlayedContracts.Sum(x => x.Value.Plays),
|
||||
ContractsCreated = _userProfile.ContractsCreated
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public int GetUserWallet(GetUserWalletRequest request)
|
||||
public Task<int> GetUserWallet(GetUserWalletRequest request)
|
||||
{
|
||||
return _userProfile.WalletAmount;
|
||||
return Task.FromResult(_userProfile.WalletAmount);
|
||||
}
|
||||
|
||||
public void InviteToCompetition(InviteToCompetitionRequest request)
|
||||
|
@ -240,7 +243,7 @@ namespace Cobra.Server.Hitman.Services
|
|||
//Do nothing
|
||||
}
|
||||
|
||||
public void UpdateUserInfo(UpdateUserInfoRequest request)
|
||||
public Task UpdateUserInfo(UpdateUserInfoRequest request)
|
||||
{
|
||||
SaveUserProfile(() =>
|
||||
{
|
||||
|
@ -249,6 +252,8 @@ namespace Cobra.Server.Hitman.Services
|
|||
|
||||
request.Friends.ForEach(x => _userProfile.Friends.Add(x));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void UploadContract(UploadContractRequest request)
|
||||
|
|
|
@ -287,9 +287,9 @@ namespace Cobra.Server.Hitman.Services
|
|||
return 10;
|
||||
}
|
||||
|
||||
public GetUserOverviewData GetUserOverviewData(GetUserOverviewDataRequest request)
|
||||
public Task<GetUserOverviewData> GetUserOverviewData(GetUserOverviewDataRequest request)
|
||||
{
|
||||
return new GetUserOverviewData
|
||||
return Task.FromResult(new GetUserOverviewData
|
||||
{
|
||||
ContractPlays = 1337,
|
||||
CompetitionPlays = 1337,
|
||||
|
@ -303,12 +303,12 @@ namespace Cobra.Server.Hitman.Services
|
|||
RichestRank = 1337,
|
||||
TrophiesEarned = 1337,
|
||||
WalletAmount = _options.WalletAmount
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public int GetUserWallet(GetUserWalletRequest request)
|
||||
public Task<int> GetUserWallet(GetUserWalletRequest request)
|
||||
{
|
||||
return _options.WalletAmount;
|
||||
return Task.FromResult(_options.WalletAmount);
|
||||
}
|
||||
|
||||
public void InviteToCompetition(InviteToCompetitionRequest request)
|
||||
|
@ -365,9 +365,9 @@ namespace Cobra.Server.Hitman.Services
|
|||
//Do nothing
|
||||
}
|
||||
|
||||
public void UpdateUserInfo(UpdateUserInfoRequest request)
|
||||
public Task UpdateUserInfo(UpdateUserInfoRequest request)
|
||||
{
|
||||
//Do nothing
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void UploadContract(UploadContractRequest request)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
@ -9,7 +9,6 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
<ProjectReference Include="..\Cobra.Analyzer\Cobra.Analyzer.csproj">
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
namespace Cobra.Server.Shared.Interfaces
|
||||
{
|
||||
public interface IUserService
|
||||
{
|
||||
public ulong GetCurrentUserId();
|
||||
}
|
||||
}
|
|
@ -2,6 +2,13 @@
|
|||
{
|
||||
public class Options
|
||||
{
|
||||
public enum EGameService
|
||||
{
|
||||
Mocked = 0,
|
||||
Local,
|
||||
Public
|
||||
}
|
||||
|
||||
public enum ESteamService
|
||||
{
|
||||
None = 0,
|
||||
|
@ -15,7 +22,7 @@
|
|||
public bool EnableResponseBodyLogging { get; set; } = false;
|
||||
public string MockedContractSteamId { get; set; } = "76561198161220058";
|
||||
public int WalletAmount { get; set; } = 1337;
|
||||
public bool UseCustomContracts { get; set; } = false;
|
||||
public EGameService GameService { get; set; } = EGameService.Mocked;
|
||||
public int JwtTokenExpirationInSeconds { get; set; } = 60 * 60 * 8; //NOTE: 8 hours
|
||||
public string JwtSignKey { get; set; } = Guid.NewGuid().ToString();
|
||||
public ESteamService SteamService { get; set; } = ESteamService.None;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using Cobra.Server.Shared.Models;
|
||||
using Cobra.Server.Sniper.Interfaces;
|
||||
using Cobra.Server.Sniper.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Cobra.Server.Sniper
|
||||
{
|
||||
public static class Compositions
|
||||
{
|
||||
public static void ConfigureServices(IServiceCollection services, IConfiguration configuration, Options options)
|
||||
{
|
||||
services.AddSingleton<ISniperMetadataService, SniperMetadataService>();
|
||||
services.AddSingleton<ISniperServer, MockedSniperServer>();
|
||||
}
|
||||
|
||||
public static void Configure(IServiceProvider services)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
<OutputItemType>Analyzer</OutputItemType>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Cobra.Server.Database\Cobra.Server.Database.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Shared\Cobra.Server.Shared.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Hitman\Cobra.Server.Hitman.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Sniper\Cobra.Server.Sniper.csproj" />
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
using Cobra.Server.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cobra.Server.Database
|
||||
{
|
||||
public class DatabaseContext : DbContext
|
||||
{
|
||||
public DbSet<User> Users { get; set; }
|
||||
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> dbContextOptions)
|
||||
: base(dbContextOptions)
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
// <auto-generated />
|
||||
using Cobra.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20231022225634_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.12");
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CompetitionPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ContractPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Country")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("SteamId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Trophies")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Wallet")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<ulong>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
SteamId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
DisplayName = table.Column<string>(type: "TEXT", nullable: true),
|
||||
Country = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Wallet = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
ContractPlays = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
CompetitionPlays = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Trophies = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Users", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Users");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
// <auto-generated />
|
||||
using Cobra.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Cobra.Server.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
partial class DatabaseContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "7.0.12");
|
||||
|
||||
modelBuilder.Entity("Cobra.Server.Database.Models.User", b =>
|
||||
{
|
||||
b.Property<ulong>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("CompetitionPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ContractPlays")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Country")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("SteamId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Trophies")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Wallet")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System.Security.Claims;
|
||||
|
||||
namespace Cobra.Server.Models
|
||||
{
|
||||
public class CustomIdentity : ClaimsIdentity
|
||||
{
|
||||
public override bool IsAuthenticated => true;
|
||||
|
||||
public ulong SteamId { get; init; }
|
||||
|
||||
public CustomIdentity(ulong steamId)
|
||||
{
|
||||
SteamId = steamId;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,25 @@
|
|||
using System.Security.Cryptography;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Cobra.Server.Interfaces;
|
||||
using Cobra.Server.Models;
|
||||
using Cobra.Server.Shared.Models;
|
||||
|
||||
namespace Cobra.Server.Mvc
|
||||
{
|
||||
public class SteamAuthMiddleware : IMiddleware
|
||||
{
|
||||
private class JwtToken
|
||||
private sealed class JwtToken
|
||||
{
|
||||
public class JwtTokenPayload
|
||||
{
|
||||
public ulong Uid { get; set; }
|
||||
public long Timestamp { get; set; }
|
||||
public ulong Uid { get; init; }
|
||||
public long Timestamp { get; init; }
|
||||
}
|
||||
|
||||
public JwtTokenPayload Payload { get; set; }
|
||||
public string Hash { get; set; }
|
||||
public JwtTokenPayload Payload { get; init; }
|
||||
public string Hash { get; init; }
|
||||
}
|
||||
|
||||
private const string REQUEST_HEADER_OSAUTHPROVIDER = "OS-AuthProvider";
|
||||
|
@ -45,11 +47,12 @@ namespace Cobra.Server.Mvc
|
|||
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
//TODO: Move this middleware to a filter instead?
|
||||
if (
|
||||
context.Request.Path is { HasValue: true, Value: not null } &&
|
||||
!context.Request.Path.Value.StartsWith("/hm5") &&
|
||||
!context.Request.Path.Value.StartsWith("/sniper")
|
||||
!context.Request.Path.HasValue ||
|
||||
(
|
||||
!context.Request.Path.Value.StartsWith("/hm5") &&
|
||||
!context.Request.Path.Value.StartsWith("/sniper")
|
||||
)
|
||||
)
|
||||
{
|
||||
await next(context);
|
||||
|
@ -58,35 +61,49 @@ namespace Cobra.Server.Mvc
|
|||
}
|
||||
|
||||
var authProvider = context.Request.Headers[REQUEST_HEADER_OSAUTHPROVIDER];
|
||||
var authTicketData = context.Request.Headers[REQUEST_HEADER_OSAUTHTICKETDATA];
|
||||
var uid = context.Request.Headers[REQUEST_HEADER_OSUID];
|
||||
|
||||
//NOTE: Check for our own AuthProvider first
|
||||
if (authProvider == OSAUTHPROVIDER_SERVER)
|
||||
if (!TryDecodeBase64String(context.Request.Headers[REQUEST_HEADER_OSAUTHTICKETDATA], out var authTicketData))
|
||||
{
|
||||
var jwtToken = DecodeSimpleJwtToken(authTicketData);
|
||||
|
||||
if (
|
||||
jwtToken != null &&
|
||||
jwtToken.Uid == ulong.Parse(uid) &&
|
||||
DateTimeOffset.Now.ToUnixTimeSeconds() - jwtToken.Timestamp < _jwtTokenExpirationInSeconds
|
||||
)
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
|
||||
RejectRequest(context, OSERROR_EXPIRED);
|
||||
RejectRequest(context, OSERROR_FAILED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: If we didn't pass the previous check, enforce valid AuthTicketData.
|
||||
if (!ulong.TryParse(context.Request.Headers[REQUEST_HEADER_OSUID], out var steamId))
|
||||
{
|
||||
RejectRequest(context, OSERROR_FAILED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: Wrap in a try-catch to make sure unhandled situations result in a rejected response
|
||||
try
|
||||
{
|
||||
var authTicketDataBytes = Convert.FromBase64String(authTicketData);
|
||||
var steamId = ulong.Parse(uid);
|
||||
//NOTE: Check for our own AuthProvider first
|
||||
if (authProvider == OSAUTHPROVIDER_SERVER)
|
||||
{
|
||||
var jwtToken = DecodeSimpleJwtToken(authTicketData);
|
||||
|
||||
var result = await _steamService.AuthenticateUser(authTicketDataBytes, steamId);
|
||||
if (
|
||||
jwtToken != null &&
|
||||
jwtToken.Uid == steamId &&
|
||||
DateTimeOffset.Now.ToUnixTimeSeconds() - jwtToken.Timestamp < _jwtTokenExpirationInSeconds
|
||||
)
|
||||
{
|
||||
AuthenticateRequest(context, jwtToken.Uid);
|
||||
|
||||
await next(context);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
RejectRequest(context, OSERROR_EXPIRED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//NOTE: If we didn't pass the previous check, enforce valid AuthTicketData.
|
||||
var result = await _steamService.AuthenticateUser(authTicketData, steamId);
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
@ -98,6 +115,8 @@ namespace Cobra.Server.Mvc
|
|||
|
||||
context.Response.Headers[RESPONSE_HEADER_OSAUTHRESPONSE] = jwtToken;
|
||||
|
||||
AuthenticateRequest(context, steamId);
|
||||
|
||||
await next(context);
|
||||
|
||||
return;
|
||||
|
@ -112,12 +131,43 @@ namespace Cobra.Server.Mvc
|
|||
RejectRequest(context, OSERROR_FAILED);
|
||||
}
|
||||
|
||||
private static void AuthenticateRequest(HttpContext context, ulong steamId)
|
||||
{
|
||||
context.User = new ClaimsPrincipal(new CustomIdentity(steamId));
|
||||
}
|
||||
|
||||
private static void RejectRequest(HttpContext context, int osError)
|
||||
{
|
||||
context.Response.StatusCode = 403;
|
||||
context.Response.Headers[RESPONSE_HEADER_OSERROR] = osError.ToString();
|
||||
}
|
||||
|
||||
private static bool TryDecodeBase64String(string base64String, out byte[] bytes)
|
||||
{
|
||||
if (base64String == null)
|
||||
{
|
||||
bytes = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Span<byte> bytesBuffer = stackalloc byte[base64String.Length];
|
||||
|
||||
if (
|
||||
!Convert.TryFromBase64String(base64String, bytesBuffer, out var bytesWritten) ||
|
||||
bytesWritten == 0
|
||||
)
|
||||
{
|
||||
bytes = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = bytesBuffer[..bytesWritten].ToArray();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private string EncodeSimpleJwtToken(JwtToken.JwtTokenPayload payload)
|
||||
{
|
||||
using var hasher = new HMACSHA256(_jwtSignKey);
|
||||
|
@ -142,12 +192,10 @@ namespace Cobra.Server.Mvc
|
|||
);
|
||||
}
|
||||
|
||||
private JwtToken.JwtTokenPayload DecodeSimpleJwtToken(string simpleJwtToken)
|
||||
private JwtToken.JwtTokenPayload DecodeSimpleJwtToken(byte[] simpleJwtToken)
|
||||
{
|
||||
var jwtToken = JsonSerializer.Deserialize<JwtToken>(
|
||||
Encoding.UTF8.GetString(
|
||||
Convert.FromBase64String(simpleJwtToken)
|
||||
)
|
||||
Encoding.UTF8.GetString(simpleJwtToken)
|
||||
);
|
||||
|
||||
using var hasher = new HMACSHA256(_jwtSignKey);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using Cobra.Server.Models;
|
||||
using Cobra.Server.Shared.Interfaces;
|
||||
|
||||
namespace Cobra.Server.Services
|
||||
{
|
||||
public class UserService : IUserService
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public UserService(
|
||||
IHttpContextAccessor httpContextAccessor
|
||||
)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public ulong GetCurrentUserId()
|
||||
{
|
||||
return (_httpContextAccessor.HttpContext?.User.Identity as CustomIdentity)?.SteamId ?? 0UL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,14 @@
|
|||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
using Cobra.Server.Database;
|
||||
using Cobra.Server.Edm.Json;
|
||||
using Cobra.Server.Hitman.Interfaces;
|
||||
using Cobra.Server.Hitman.Services;
|
||||
using Cobra.Server.Interfaces;
|
||||
using Cobra.Server.Mvc;
|
||||
using Cobra.Server.Services;
|
||||
using Cobra.Server.Shared.Interfaces;
|
||||
using Cobra.Server.Shared.Models;
|
||||
using Cobra.Server.Sniper.Interfaces;
|
||||
using Cobra.Server.Sniper.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using DatabaseCompositions = Cobra.Server.Database.Compositions;
|
||||
using HitmanCompositions = Cobra.Server.Hitman.Compositions;
|
||||
using SniperCompositions = Cobra.Server.Sniper.Compositions;
|
||||
|
||||
namespace Cobra.Server
|
||||
{
|
||||
|
@ -53,61 +50,48 @@ namespace Cobra.Server
|
|||
options.JsonSerializerOptions.Converters.Add(new IntegerToStringConverter());
|
||||
});
|
||||
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
var options = _configuration
|
||||
.GetSection("Options")
|
||||
.Get<Options>();
|
||||
|
||||
services.AddSingleton(options);
|
||||
|
||||
services.AddDbContext<DatabaseContext>(optionsBuilder =>
|
||||
{
|
||||
optionsBuilder.UseSqlite(_configuration.GetConnectionString("CobraDatabase"));
|
||||
});
|
||||
|
||||
//Shared
|
||||
services.AddSingleton<ISimpleLogger>(_ => new SimpleLogger("Data"));
|
||||
services.AddSingleton<IUserService, UserService>();
|
||||
|
||||
services.AddSingleton<IHitmanMetadataService, HitmanMetadataService>();
|
||||
services.AddSingleton<ISniperMetadataService, SniperMetadataService>();
|
||||
switch (options.SteamService)
|
||||
{
|
||||
case Options.ESteamService.GameServer:
|
||||
services.AddSingleton<ISteamService, SteamGameServerService>();
|
||||
break;
|
||||
case Options.ESteamService.WebApi:
|
||||
services.AddSingleton<ISteamService, SteamWebApiService>();
|
||||
break;
|
||||
}
|
||||
|
||||
//Middleware
|
||||
services.AddTransient<FixAddMetricsContentTypeMiddleware>();
|
||||
services.AddTransient<RequestResponseLoggerMiddleware>();
|
||||
services.AddTransient<SteamAuthMiddleware>();
|
||||
|
||||
services.AddSingleton<IContractsService, ContractsService>();
|
||||
|
||||
if (options.UseCustomContracts)
|
||||
{
|
||||
services.AddSingleton<IHitmanServer, LocalHitmanServer>();
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IHitmanServer, MockedHitmanServer>();
|
||||
}
|
||||
|
||||
services.AddSingleton<ISniperServer, MockedSniperServer>();
|
||||
|
||||
if (options.SteamService == Options.ESteamService.GameServer)
|
||||
{
|
||||
services.AddSingleton<ISteamService, SteamGameServerService>();
|
||||
}
|
||||
else if (options.SteamService == Options.ESteamService.WebApi)
|
||||
{
|
||||
services.AddSingleton<ISteamService, SteamWebApiService>();
|
||||
}
|
||||
//Compositions
|
||||
DatabaseCompositions.ConfigureServices(services, _configuration, options);
|
||||
HitmanCompositions.ConfigureServices(services, _configuration, options);
|
||||
SniperCompositions.ConfigureServices(services, _configuration, options);
|
||||
}
|
||||
|
||||
public void Configure(
|
||||
IApplicationBuilder app,
|
||||
Options options,
|
||||
IHitmanServer hitmanServer,
|
||||
ISniperServer sniperServer,
|
||||
DatabaseContext databaseContext
|
||||
IServiceProvider services,
|
||||
Options options
|
||||
)
|
||||
{
|
||||
databaseContext.Database.Migrate();
|
||||
|
||||
hitmanServer.Initialize();
|
||||
sniperServer.Initialize();
|
||||
DatabaseCompositions.Configure(services);
|
||||
HitmanCompositions.Configure(services);
|
||||
SniperCompositions.Configure(services);
|
||||
|
||||
if (options.FixAddMetricsContentType)
|
||||
{
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
"EnableRequestLogging": true,
|
||||
"EnableRequestBodyLogging": false,
|
||||
"EnableResponseBodyLogging": false,
|
||||
"MockedContractSteamId": "76561198161220058",
|
||||
"WalletAmount": 1337,
|
||||
"UseCustomContracts": true
|
||||
"GameService": "Public",
|
||||
"SteamService": "GameServer"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NoWarn>JSON002</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
|
||||
<PackageReference Include="Moq" Version="4.20.69" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
@ -29,6 +31,7 @@
|
|||
</ProjectReference>
|
||||
<ProjectReference Include="..\Cobra.Server.Edm\Cobra.Server.Edm.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server.Hitman\Cobra.Server.Hitman.csproj" />
|
||||
<ProjectReference Include="..\Cobra.Server\Cobra.Server.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -6,9 +6,9 @@ using Cobra.Server.Edm.Interfaces;
|
|||
using Cobra.Server.Edm.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Cobra.Test
|
||||
namespace Cobra.Test.Edm
|
||||
{
|
||||
public class BaseControllerTests
|
||||
public class BaseEdmControllerTests
|
||||
{
|
||||
public class TestClass
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace Cobra.Test
|
|||
|
||||
private readonly TestController _testController;
|
||||
|
||||
public BaseControllerTests()
|
||||
public BaseEdmControllerTests()
|
||||
{
|
||||
_testController = new TestController();
|
||||
}
|
|
@ -5,7 +5,7 @@ using Cobra.Server.Edm.Json;
|
|||
using Cobra.Server.Hitman.Models;
|
||||
using Nullable = Cobra.Server.Edm.Enums.Nullable;
|
||||
|
||||
namespace Cobra.Test
|
||||
namespace Cobra.Test.Edm
|
||||
{
|
||||
public class JsonConverterTests
|
||||
{
|
|
@ -3,8 +3,9 @@ using Cobra.Server.Edm.Enums;
|
|||
using Cobra.Server.Edm.Interfaces;
|
||||
using Cobra.Server.Edm.Models.Base;
|
||||
using Cobra.Server.Edm.Services;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Cobra.Test
|
||||
namespace Cobra.Test.Edm
|
||||
{
|
||||
public class MetadataServiceTests
|
||||
{
|
||||
|
@ -29,6 +30,7 @@ namespace Cobra.Test
|
|||
protected override List<Type> GetEdmFunctionImports() => _edmFunctionImports;
|
||||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
[EdmEntity("EntityTest")]
|
||||
public class TestEntityValid : IEdmEntity
|
||||
{
|
||||
|
@ -52,6 +54,7 @@ namespace Cobra.Test
|
|||
//Do nothing
|
||||
}
|
||||
|
||||
[ExcludeFromCodeCoverage]
|
||||
[EdmFunctionImport("FunctionImportTest", HttpMethods.GET, "Test.EntityTest")]
|
||||
public class TestFunctionImportValid : IEdmFunctionImport
|
||||
{
|
|
@ -1,4 +1,5 @@
|
|||
using System.Globalization;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Cobra.Server.Edm.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
@ -6,7 +7,7 @@ using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Cobra.Test
|
||||
namespace Cobra.Test.Edm
|
||||
{
|
||||
public class ModelBinderTests
|
||||
{
|
||||
|
@ -16,6 +17,7 @@ namespace Cobra.Test
|
|||
}
|
||||
|
||||
//ReSharper disable UnassignedGetOnlyAutoProperty
|
||||
[ExcludeFromCodeCoverage]
|
||||
public class TestModelMetadata : ModelMetadata
|
||||
{
|
||||
public override IReadOnlyDictionary<object, object> AdditionalValues { get; }
|
|
@ -0,0 +1,14 @@
|
|||
using System.Linq.Expressions;
|
||||
using Moq;
|
||||
|
||||
namespace Cobra.Test.Extensions
|
||||
{
|
||||
public static class MoqExtensions
|
||||
{
|
||||
public static Expression<Func<T, TResult>> Expression<T, TResult>(this Mock<T> mock, Expression<Func<T, TResult>> expression)
|
||||
where T : class
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace Cobra.Test.Hitman
|
||||
{
|
||||
public class TempTests
|
||||
{
|
||||
[Fact]
|
||||
public void Test()
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,345 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Cobra.Server.Interfaces;
|
||||
using Cobra.Server.Models;
|
||||
using Cobra.Server.Mvc;
|
||||
using Cobra.Server.Shared.Models;
|
||||
using Cobra.Test.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Moq;
|
||||
|
||||
namespace Cobra.Test.Server
|
||||
{
|
||||
public class SteamAuthMiddlewareTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("/")]
|
||||
[InlineData("/test")]
|
||||
[InlineData("/unknown")]
|
||||
public async Task PathWithUnknownPrefix_ShouldBe_Skipped(string path)
|
||||
{
|
||||
var (_, steamAuthMiddleware, httpContext) = SetupInstances(path);
|
||||
|
||||
HttpContext nextContext = null;
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, context =>
|
||||
{
|
||||
nextContext = context;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
Assert.NotNull(nextContext);
|
||||
Assert.Equal(httpContext, nextContext);
|
||||
Assert.False(httpContext.User.Identity?.IsAuthenticated);
|
||||
Assert.Equal(200, httpContext.Response.StatusCode);
|
||||
Assert.False(httpContext.Response.Headers.ContainsKey("OS-Error"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null, 47)]
|
||||
[InlineData("unknown", 47)]
|
||||
[InlineData("unknown", 101)]
|
||||
[InlineData("unknown", 1337)]
|
||||
public async Task UnknownAuthProviderWithValidAuthentication_ShouldBe_Authenticated(string authProvider, ulong userId)
|
||||
{
|
||||
var (steamServiceMock, steamAuthMiddleware, httpContext) = SetupInstances(
|
||||
"/hm5",
|
||||
authProvider: authProvider,
|
||||
authTicketData: Convert.ToBase64String(Encoding.UTF8.GetBytes(userId.ToString())),
|
||||
uid: userId.ToString()
|
||||
);
|
||||
|
||||
var steamServiceExpression = steamServiceMock.Expression(x => x.AuthenticateUser(
|
||||
It.IsAny<byte[]>(),
|
||||
It.IsAny<ulong>()
|
||||
));
|
||||
|
||||
steamServiceMock.Setup(steamServiceExpression).ReturnsAsync(true);
|
||||
|
||||
HttpContext nextContext = null;
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, context =>
|
||||
{
|
||||
nextContext = context;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
steamServiceMock.Verify(steamServiceExpression, Times.Once);
|
||||
|
||||
Assert.NotNull(nextContext);
|
||||
Assert.Equal(httpContext, nextContext);
|
||||
Assert.True(httpContext.User.Identity!.IsAuthenticated);
|
||||
Assert.Equal(userId, ((CustomIdentity)httpContext.User.Identity).SteamId);
|
||||
Assert.True(httpContext.Response.Headers.ContainsKey("OS-AuthResponse"));
|
||||
Assert.Equal(200, httpContext.Response.StatusCode);
|
||||
Assert.False(httpContext.Response.Headers.ContainsKey("OS-Error"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("invalid")]
|
||||
public async Task UnknownAuthProviderWithInvalidAuthTicketData_ShouldBe_Rejected(string authTicketData)
|
||||
{
|
||||
await TestForRejectedUnknownAuthProvider(
|
||||
"47",
|
||||
authTicketData
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("invalid")]
|
||||
public async Task UnknownAuthProviderWithInvalidUserId_ShouldBe_Rejected(string userId)
|
||||
{
|
||||
await TestForRejectedUnknownAuthProvider(
|
||||
userId,
|
||||
Convert.ToBase64String(Encoding.UTF8.GetBytes("47"))
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(47)]
|
||||
[InlineData(101)]
|
||||
[InlineData(1337)]
|
||||
public async Task UnknownAuthProviderWithAuthenticationForOtherUser_ShouldBe_Rejected(ulong userId)
|
||||
{
|
||||
await TestForRejectedUnknownAuthProvider(
|
||||
userId.ToString(),
|
||||
Convert.ToBase64String(
|
||||
Encoding.UTF8.GetBytes((userId + 1).ToString())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(47)]
|
||||
[InlineData(101)]
|
||||
[InlineData(1337)]
|
||||
public async Task KnownAuthProviderWithValidAuthentication_ShouldBe_Authenticated(ulong userId)
|
||||
{
|
||||
var authTicketData = await GetAuthTicketDataForUserId(userId);
|
||||
|
||||
var (_, steamAuthMiddleware, httpContext) = SetupInstances(
|
||||
"/hm5",
|
||||
authProvider: "6",
|
||||
authTicketData: authTicketData,
|
||||
uid: userId.ToString(),
|
||||
jwtTokenExpirationInSeconds: int.MaxValue
|
||||
);
|
||||
|
||||
HttpContext nextContext = null;
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, context =>
|
||||
{
|
||||
nextContext = context;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
Assert.NotNull(nextContext);
|
||||
Assert.Equal(httpContext, nextContext);
|
||||
Assert.True(httpContext.User.Identity!.IsAuthenticated);
|
||||
Assert.Equal(userId, ((CustomIdentity)httpContext.User.Identity).SteamId);
|
||||
Assert.False(httpContext.Response.Headers.ContainsKey("OS-AuthResponse"));
|
||||
Assert.Equal(200, httpContext.Response.StatusCode);
|
||||
Assert.False(httpContext.Response.Headers.ContainsKey("OS-Error"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("invalid")]
|
||||
public async Task KnownAuthProviderWithInvalidAuthTicketData_ShouldBe_Rejected(string authTicketData)
|
||||
{
|
||||
await TestForRejectedKnownAuthProvider(
|
||||
"47",
|
||||
authTicketData,
|
||||
int.MaxValue,
|
||||
"1"
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("invalid")]
|
||||
public async Task KnownAuthProviderWithInvalidUserId_ShouldBe_Rejected(string userId)
|
||||
{
|
||||
var authTicketData = await GetAuthTicketDataForUserId(47);
|
||||
|
||||
await TestForRejectedKnownAuthProvider(
|
||||
userId,
|
||||
authTicketData,
|
||||
int.MaxValue,
|
||||
"1"
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(47)]
|
||||
[InlineData(101)]
|
||||
[InlineData(1337)]
|
||||
public async Task KnownAuthProviderWithAuthenticationForOtherUser_ShouldBe_Rejected(ulong userId)
|
||||
{
|
||||
var authTicketData = await GetAuthTicketDataForUserId(userId + 1);
|
||||
|
||||
//NOTE: We could argue that a user mismatch should be error code 1 instead
|
||||
await TestForRejectedKnownAuthProvider(
|
||||
userId.ToString(),
|
||||
authTicketData,
|
||||
int.MaxValue,
|
||||
"2"
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(47)]
|
||||
[InlineData(101)]
|
||||
[InlineData(1337)]
|
||||
public async Task KnownAuthProviderWithExpiredAuthentication_ShouldBe_Rejected(ulong userId)
|
||||
{
|
||||
var authTicketData = await GetAuthTicketDataForUserId(userId);
|
||||
|
||||
await TestForRejectedKnownAuthProvider(
|
||||
userId.ToString(),
|
||||
authTicketData,
|
||||
0,
|
||||
"2"
|
||||
);
|
||||
}
|
||||
|
||||
private static (
|
||||
Mock<ISteamService> steamServiceMock,
|
||||
SteamAuthMiddleware steamAuthMiddleware,
|
||||
DefaultHttpContext httpContext
|
||||
) SetupInstances(
|
||||
string path,
|
||||
string authProvider = "",
|
||||
string authTicketData = "",
|
||||
string uid = "",
|
||||
int jwtTokenExpirationInSeconds = 0,
|
||||
string jwtSignKey = "test"
|
||||
)
|
||||
{
|
||||
var steamServiceMock = new Mock<ISteamService>();
|
||||
|
||||
var steamAuthMiddleware = new SteamAuthMiddleware(
|
||||
steamServiceMock.Object,
|
||||
new Options
|
||||
{
|
||||
JwtTokenExpirationInSeconds = jwtTokenExpirationInSeconds,
|
||||
JwtSignKey = jwtSignKey
|
||||
}
|
||||
);
|
||||
|
||||
var httpContext = new DefaultHttpContext
|
||||
{
|
||||
Request =
|
||||
{
|
||||
Path = path,
|
||||
Headers =
|
||||
{
|
||||
{ "OS-AuthProvider", authProvider},
|
||||
{ "OS-AuthTicketData", authTicketData},
|
||||
{ "OS-UID", uid}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (steamServiceMock, steamAuthMiddleware, httpContext);
|
||||
}
|
||||
|
||||
private static async Task TestForRejectedUnknownAuthProvider(
|
||||
string userId,
|
||||
string authTicketData
|
||||
)
|
||||
{
|
||||
var (steamServiceMock, steamAuthMiddleware, httpContext) = SetupInstances(
|
||||
"/hm5",
|
||||
authProvider: "unknown",
|
||||
uid: userId,
|
||||
authTicketData: authTicketData
|
||||
);
|
||||
|
||||
var steamServiceExpression = steamServiceMock.Expression(x => x.AuthenticateUser(
|
||||
It.IsAny<byte[]>(),
|
||||
It.IsAny<ulong>()
|
||||
));
|
||||
|
||||
steamServiceMock.Setup(steamServiceExpression).ReturnsAsync(false);
|
||||
|
||||
HttpContext nextContext = null;
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, [ExcludeFromCodeCoverage] (context) =>
|
||||
{
|
||||
nextContext = context;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
steamServiceMock.Verify(steamServiceExpression, Times.AtMost(1));
|
||||
|
||||
Assert.Null(nextContext);
|
||||
Assert.False(httpContext.User.Identity?.IsAuthenticated);
|
||||
Assert.Equal(403, httpContext.Response.StatusCode);
|
||||
Assert.Equal("1", httpContext.Response.Headers["OS-Error"]);
|
||||
}
|
||||
|
||||
private static async Task TestForRejectedKnownAuthProvider(
|
||||
string userId,
|
||||
string authTicketData,
|
||||
int jwtTokenExpirationInSeconds,
|
||||
string expectedErrorCode
|
||||
)
|
||||
{
|
||||
var (_, steamAuthMiddleware, httpContext) = SetupInstances(
|
||||
"/hm5",
|
||||
authProvider: "6",
|
||||
authTicketData: authTicketData,
|
||||
uid: userId,
|
||||
jwtTokenExpirationInSeconds: jwtTokenExpirationInSeconds
|
||||
);
|
||||
|
||||
HttpContext nextContext = null;
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, [ExcludeFromCodeCoverage] (context) =>
|
||||
{
|
||||
nextContext = context;
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
Assert.Null(nextContext);
|
||||
Assert.False(httpContext.User.Identity?.IsAuthenticated);
|
||||
Assert.Equal(403, httpContext.Response.StatusCode);
|
||||
Assert.Equal(expectedErrorCode, httpContext.Response.Headers["OS-Error"]);
|
||||
}
|
||||
|
||||
//TODO: Maybe add a service for the encoding/decoding of tokens, so it can be independently used/tested/mocked?
|
||||
private static async Task<string> GetAuthTicketDataForUserId(ulong userId)
|
||||
{
|
||||
var (steamServiceMock, steamAuthMiddleware, httpContext) = SetupInstances(
|
||||
"/hm5",
|
||||
authTicketData: Convert.ToBase64String(Encoding.UTF8.GetBytes(userId.ToString())),
|
||||
uid: userId.ToString()
|
||||
);
|
||||
|
||||
var steamServiceExpression = steamServiceMock.Expression(x => x.AuthenticateUser(
|
||||
It.IsAny<byte[]>(),
|
||||
It.IsAny<ulong>()
|
||||
));
|
||||
|
||||
steamServiceMock.Setup(steamServiceExpression).ReturnsAsync(true);
|
||||
|
||||
await steamAuthMiddleware.InvokeAsync(httpContext, _ => Task.CompletedTask);
|
||||
|
||||
return httpContext.Response.Headers["OS-AuthResponse"].Single();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace Cobra.Test.Sniper
|
||||
{
|
||||
public class TempTests
|
||||
{
|
||||
[Fact]
|
||||
public void Test()
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue