mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-19 11:41:30 +00:00
Merge branch 'main' into lbp3-collections
This commit is contained in:
commit
757a96d435
39 changed files with 840 additions and 59 deletions
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
|
@ -13,9 +13,9 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os:
|
os:
|
||||||
- { prettyName: Windows, fullName: windows-latest, database: true }
|
- { prettyName: Windows, fullName: windows-latest, database: true, webTest: false }
|
||||||
- { prettyName: macOS, fullName: macos-latest, database: true }
|
- { prettyName: macOS, fullName: macos-latest, database: true, webTest: false }
|
||||||
- { prettyName: Linux, fullName: ubuntu-latest, database: true }
|
- { prettyName: Linux, fullName: ubuntu-latest, database: true, webTest: true }
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
env:
|
env:
|
||||||
DB_DATABASE: lighthouse
|
DB_DATABASE: lighthouse
|
||||||
|
@ -44,10 +44,18 @@ jobs:
|
||||||
- name: Compile
|
- name: Compile
|
||||||
run: dotnet build -c Debug
|
run: dotnet build -c Debug
|
||||||
|
|
||||||
- name: Test
|
- name: Run tests on ProjectLighthouse.Tests
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx"
|
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-Tests.trx" ProjectLighthouse.Tests
|
||||||
|
|
||||||
|
- name: Run tests on ProjectLighthouse.Tests.GameApiTests
|
||||||
|
continue-on-error: true
|
||||||
|
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-GameApiTests.trx" ProjectLighthouse.Tests.GameApiTests
|
||||||
|
|
||||||
|
- name: Run tests on ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
if: ${{ matrix.os.webTest }}
|
||||||
|
continue-on-error: true
|
||||||
|
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-WebsiteTests.trx" ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
|
||||||
# Attempt to upload results even if test fails.
|
# Attempt to upload results even if test fails.
|
||||||
# https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always
|
# https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always
|
||||||
|
@ -56,7 +64,7 @@ jobs:
|
||||||
if: ${{ always() }}
|
if: ${{ always() }}
|
||||||
with:
|
with:
|
||||||
name: lighthouse-test-results-${{matrix.os.prettyName}}
|
name: lighthouse-test-results-${{matrix.os.prettyName}}
|
||||||
path: ${{github.workspace}}/TestResults-${{matrix.os.prettyName}}.trx
|
path: ${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-*.trx
|
||||||
|
|
||||||
- name: Process Test Results
|
- name: Process Test Results
|
||||||
id: process-trx
|
id: process-trx
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<jdbc-url>jdbc:mysql://localhost:3306/lighthouse</jdbc-url>
|
<jdbc-url>jdbc:mysql://localhost:3306/lighthouse</jdbc-url>
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
</data-source>
|
</data-source>
|
||||||
<data-source source="LOCAL" name="Lighthouse Production" uuid="b323608d-d984-40d0-942e-2c2ea35006d8">
|
<data-source source="LOCAL" name="Lighthouse Production" read-only="true" uuid="b323608d-d984-40d0-942e-2c2ea35006d8">
|
||||||
<driver-ref>mariadb</driver-ref>
|
<driver-ref>mariadb</driver-ref>
|
||||||
<synchronize>true</synchronize>
|
<synchronize>true</synchronize>
|
||||||
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
|
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace ProjectLighthouse.Tests.GameApiTests
|
||||||
{
|
{
|
||||||
public class AuthenticationTests : LighthouseTest
|
public class AuthenticationTests : LighthouseServerTest
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldReturnErrorOnNoPostData()
|
public async Task ShouldReturnErrorOnNoPostData()
|
|
@ -1,12 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace ProjectLighthouse.Tests.GameApiTests
|
||||||
{
|
{
|
||||||
public class DatabaseTests : LighthouseTest
|
public class DatabaseTests : LighthouseServerTest
|
||||||
{
|
{
|
||||||
[DatabaseFact]
|
[DatabaseFact]
|
||||||
public async Task CanCreateUserTwice()
|
public async Task CanCreateUserTwice()
|
||||||
|
@ -21,8 +23,6 @@ namespace LBPUnion.ProjectLighthouse.Tests
|
||||||
Assert.NotNull(userB);
|
Assert.NotNull(userB);
|
||||||
|
|
||||||
await database.RemoveUser(userA); // Only remove userA since userA and userB are the same user
|
await database.RemoveUser(userA); // Only remove userA since userA and userB are the same user
|
||||||
|
|
||||||
await database.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,12 +4,13 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace ProjectLighthouse.Tests.GameApiTests
|
||||||
{
|
{
|
||||||
public class MatchTests : LighthouseTest
|
public class MatchTests : LighthouseServerTest
|
||||||
{
|
{
|
||||||
private static readonly SemaphoreSlim semaphore = new(1, 1);
|
private static readonly SemaphoreSlim semaphore = new(1, 1);
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0"/>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj"/>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\ProjectLighthouse.Tests\ExampleFiles\**">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -1,15 +1,17 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace ProjectLighthouse.Tests.GameApiTests
|
||||||
{
|
{
|
||||||
public class SlotTests : LighthouseTest
|
public class SlotTests : LighthouseServerTest
|
||||||
{
|
{
|
||||||
[DatabaseFact]
|
[DatabaseFact]
|
||||||
public async Task ShouldOnlyShowUsersLevels()
|
public async Task ShouldOnlyShowUsersLevels()
|
|
@ -3,11 +3,12 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace ProjectLighthouse.Tests.GameApiTests
|
||||||
{
|
{
|
||||||
public class UploadTests : LighthouseTest
|
public class UploadTests : LighthouseServerTest
|
||||||
{
|
{
|
||||||
public UploadTests()
|
public UploadTests()
|
||||||
{
|
{
|
64
ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs
Normal file
64
ProjectLighthouse.Tests.WebsiteTests/AdminTests.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
{
|
||||||
|
public class AdminTests : LighthouseWebTest
|
||||||
|
{
|
||||||
|
public const string AdminPanelButtonXPath = "/html/body/div/header/div/div/div/a[2]";
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldShowAdminPanelButtonWhenAdmin()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
|
||||||
|
|
||||||
|
WebToken webToken = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
UserToken = HashHelper.GenerateAuthToken(),
|
||||||
|
};
|
||||||
|
|
||||||
|
database.WebTokens.Add(webToken);
|
||||||
|
user.IsAdmin = true;
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/");
|
||||||
|
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
|
||||||
|
this.Driver.Navigate().Refresh();
|
||||||
|
|
||||||
|
Assert.Contains("Admin Panel", this.Driver.FindElement(By.XPath(AdminPanelButtonXPath)).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldNotShowAdminPanelButtonWhenNotAdmin()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
|
||||||
|
|
||||||
|
WebToken webToken = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
UserToken = HashHelper.GenerateAuthToken(),
|
||||||
|
};
|
||||||
|
|
||||||
|
database.WebTokens.Add(webToken);
|
||||||
|
user.IsAdmin = false;
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/");
|
||||||
|
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
|
||||||
|
this.Driver.Navigate().Refresh();
|
||||||
|
|
||||||
|
Assert.DoesNotContain("Admin Panel", this.Driver.FindElement(By.XPath(AdminPanelButtonXPath)).Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs
Normal file
106
ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
{
|
||||||
|
public class AuthenticationTests : LighthouseWebTest
|
||||||
|
{
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldLoginWithPassword()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
|
||||||
|
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash(HashHelper.Sha256Hash(password)));
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(user.Username);
|
||||||
|
this.Driver.FindElement(By.Id("password")).SendKeys(password);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
|
||||||
|
Assert.NotNull(webToken);
|
||||||
|
|
||||||
|
await database.RemoveUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldNotLoginWithNoPassword()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("just like the hindenberg,"));
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(user.Username);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
|
||||||
|
Assert.Null(webToken);
|
||||||
|
|
||||||
|
await database.RemoveUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldNotLoginWithWrongPassword()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(user.Username);
|
||||||
|
this.Driver.FindElement(By.Id("password")).SendKeys("nah man");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId);
|
||||||
|
Assert.Null(webToken);
|
||||||
|
|
||||||
|
await database.RemoveUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldLoginWithInjectedCookie()
|
||||||
|
{
|
||||||
|
const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/p[1]/b";
|
||||||
|
|
||||||
|
await using Database database = new();
|
||||||
|
Random random = new();
|
||||||
|
User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure"));
|
||||||
|
|
||||||
|
WebToken webToken = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
UserToken = HashHelper.GenerateAuthToken(),
|
||||||
|
};
|
||||||
|
|
||||||
|
database.WebTokens.Add(webToken);
|
||||||
|
await database.SaveChangesAsync();
|
||||||
|
|
||||||
|
INavigation navigation = this.Driver.Navigate();
|
||||||
|
|
||||||
|
navigation.GoToUrl(this.BaseAddress + "/");
|
||||||
|
this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken));
|
||||||
|
Assert.Throws<NoSuchElementException>(() => this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)));
|
||||||
|
navigation.Refresh();
|
||||||
|
Assert.True(this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text == user.Username);
|
||||||
|
|
||||||
|
await database.RemoveUser(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs
Normal file
50
ProjectLighthouse.Tests.WebsiteTests/LighthouseWebTest.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Chrome;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
{
|
||||||
|
[Collection(nameof(LighthouseWebTest))]
|
||||||
|
public class LighthouseWebTest : IDisposable
|
||||||
|
{
|
||||||
|
public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup<TestStartup>().UseWebRoot("StaticFiles").Build();
|
||||||
|
public readonly string BaseAddress;
|
||||||
|
|
||||||
|
public readonly IWebDriver Driver;
|
||||||
|
|
||||||
|
public LighthouseWebTest()
|
||||||
|
{
|
||||||
|
this.WebHost.Start();
|
||||||
|
|
||||||
|
IServerAddressesFeature? serverAddressesFeature = WebHost.ServerFeatures.Get<IServerAddressesFeature>();
|
||||||
|
if (serverAddressesFeature == null) throw new ArgumentNullException();
|
||||||
|
|
||||||
|
this.BaseAddress = serverAddressesFeature.Addresses.First();
|
||||||
|
|
||||||
|
ChromeOptions chromeOptions = new();
|
||||||
|
if (Convert.ToBoolean(Environment.GetEnvironmentVariable("CI") ?? "false"))
|
||||||
|
{
|
||||||
|
chromeOptions.AddArgument("headless");
|
||||||
|
chromeOptions.AddArgument("no-sandbox");
|
||||||
|
chromeOptions.AddArgument("disable-dev-shm-usage");
|
||||||
|
Console.WriteLine("We are in a CI environment, so chrome headless mode has been enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Driver = new ChromeDriver(chromeOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.Driver.Close();
|
||||||
|
this.Driver.Dispose();
|
||||||
|
this.WebHost.Dispose();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0"/>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
|
||||||
|
<PackageReference Include="Selenium.WebDriver" Version="4.1.0"/>
|
||||||
|
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="96.0.4664.4500"/>
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1"/>
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj"/>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
84
ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs
Normal file
84
ProjectLighthouse.Tests.WebsiteTests/RegisterTests.cs
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.WebsiteTests
|
||||||
|
{
|
||||||
|
public class RegisterTests : LighthouseWebTest
|
||||||
|
{
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldRegister()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
|
||||||
|
string username = "unitTestUser" + new Random().Next();
|
||||||
|
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(username);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("password")).SendKeys(password);
|
||||||
|
this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
|
Assert.NotNull(user);
|
||||||
|
|
||||||
|
await database.RemoveUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldNotRegisterWithMismatchingPasswords()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
|
||||||
|
string username = "unitTestUser" + new Random().Next();
|
||||||
|
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(username);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("password")).SendKeys(password);
|
||||||
|
this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password + "a");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
|
Assert.Null(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DatabaseFact]
|
||||||
|
public async Task ShouldNotRegisterWithTakenUsername()
|
||||||
|
{
|
||||||
|
await using Database database = new();
|
||||||
|
|
||||||
|
string username = "unitTestUser" + new Random().Next();
|
||||||
|
string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray());
|
||||||
|
|
||||||
|
await database.CreateUser(username, HashHelper.BCryptHash(password));
|
||||||
|
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
|
Assert.NotNull(user);
|
||||||
|
|
||||||
|
this.Driver.Navigate().GoToUrl(this.BaseAddress + "/register");
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("text")).SendKeys(username);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("password")).SendKeys(password);
|
||||||
|
this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password);
|
||||||
|
|
||||||
|
this.Driver.FindElement(By.Id("submit")).Click();
|
||||||
|
|
||||||
|
Assert.Contains("The username you've chosen is already taken.", this.Driver.PageSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,15 +14,14 @@ using Microsoft.EntityFrameworkCore;
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace LBPUnion.ProjectLighthouse.Tests
|
||||||
{
|
{
|
||||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||||
public class LighthouseTest
|
public class LighthouseServerTest
|
||||||
{
|
{
|
||||||
public readonly HttpClient Client;
|
public readonly HttpClient Client;
|
||||||
public readonly TestServer Server;
|
public readonly TestServer Server;
|
||||||
|
|
||||||
public LighthouseTest()
|
public LighthouseServerTest()
|
||||||
{
|
{
|
||||||
this.Server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
|
this.Server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
|
||||||
|
|
||||||
this.Client = this.Server.CreateClient();
|
this.Client = this.Server.CreateClient();
|
||||||
}
|
}
|
||||||
public async Task<HttpResponseMessage> AuthenticateResponse(int number = -1, bool createUser = true)
|
public async Task<HttpResponseMessage> AuthenticateResponse(int number = -1, bool createUser = true)
|
|
@ -32,9 +32,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
|
||||||
<Content Include="ExampleFiles\**">
|
<Content Include="ExampleFiles\**">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -4,7 +4,7 @@ using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests
|
namespace LBPUnion.ProjectLighthouse.Tests
|
||||||
{
|
{
|
||||||
public class SerializerTests : LighthouseTest
|
public class SerializerTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public void BlankElementWorks()
|
public void BlankElementWorks()
|
|
@ -4,6 +4,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse", "Projec
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests", "ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj", "{AFC74569-B289-4ACC-B21C-313A3A62C017}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests", "ProjectLighthouse.Tests\ProjectLighthouse.Tests.csproj", "{AFC74569-B289-4ACC-B21C-313A3A62C017}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D360C08E-EA47-43AC-A566-FDF413442980}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.GameApiTests", "ProjectLighthouse.Tests.GameApiTests\ProjectLighthouse.Tests.GameApiTests.csproj", "{200EED99-FE3E-45C6-A51E-76ED9819CA2B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.WebsiteTests", "ProjectLighthouse.Tests.WebsiteTests\ProjectLighthouse.Tests.WebsiteTests.csproj", "{CF65EB5B-5364-4D2A-8639-F147A67F08E7}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -17,6 +23,16 @@ Global
|
||||||
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{AFC74569-B289-4ACC-B21C-313A3A62C017}.Release|Any CPU.Build.0 = Release|Any CPU
|
{200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980}
|
||||||
|
{200EED99-FE3E-45C6-A51E-76ED9819CA2B} = {D360C08E-EA47-43AC-A566-FDF413442980}
|
||||||
|
{CF65EB5B-5364-4D2A-8639-F147A67F08E7} = {D360C08E-EA47-43AC-A566-FDF413442980}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -90,6 +90,7 @@
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Affero/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Affero/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=airfryer/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=airfryer/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=asdf/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCAS/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCAS/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCES/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCES/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCET/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCET/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token, true);
|
User? user = await this.database.UserFromGameToken(token, true);
|
||||||
if (user == null)
|
|
||||||
|
if (user == null || user.Banned)
|
||||||
{
|
{
|
||||||
Logger.Log("unable to find a user from a token, rejecting login", LoggerLevelLogin.Instance);
|
Logger.Log("unable to find a user from a token, rejecting login", LoggerLevelLogin.Instance);
|
||||||
return this.StatusCode(403, "");
|
return this.StatusCode(403, "");
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
||||||
User? user = await this.database.UserFromGameRequest(this.Request);
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
return this.Ok(ServerSettings.Instance.EulaText + "\n" + $"{EulaHelper.License}\n");
|
return this.Ok($"{EulaHelper.License}\n{ServerSettings.Instance.EulaText}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("announce")]
|
[HttpGet("announce")]
|
||||||
|
@ -47,19 +47,24 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
||||||
GameToken gameToken = userAndToken.Value.Item2;
|
GameToken gameToken = userAndToken.Value.Item2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
string announceText = ServerSettings.Instance.AnnounceText;
|
||||||
|
|
||||||
|
announceText = announceText.Replace("%user", user.Username);
|
||||||
|
announceText = announceText.Replace("%id", user.UserId.ToString());
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok
|
||||||
(
|
(
|
||||||
$"You are now logged in as {user.Username}.\n\n" +
|
announceText +
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
"---DEBUG INFO---\n" +
|
"\n\n---DEBUG INFO---\n" +
|
||||||
$"user.UserId: {user.UserId}\n" +
|
$"user.UserId: {user.UserId}\n" +
|
||||||
$"token.Approved: {gameToken.Approved}\n" +
|
$"token.Approved: {gameToken.Approved}\n" +
|
||||||
$"token.Used: {gameToken.Used}\n" +
|
$"token.Used: {gameToken.Used}\n" +
|
||||||
$"token.UserLocation: {gameToken.UserLocation}\n" +
|
$"token.UserLocation: {gameToken.UserLocation}\n" +
|
||||||
$"token.GameVersion: {gameToken.GameVersion}\n" +
|
$"token.GameVersion: {gameToken.GameVersion}\n" +
|
||||||
"---DEBUG INFO---\n\n" +
|
"---DEBUG INFO---" +
|
||||||
#endif
|
#endif
|
||||||
ServerSettings.Instance.EulaText
|
"\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,21 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
||||||
|
|
||||||
[HttpGet("slots/lbp2cool")]
|
[HttpGet("slots/lbp2cool")]
|
||||||
[HttpGet("slots/cool")]
|
[HttpGet("slots/cool")]
|
||||||
public async Task<IActionResult> CoolSlots([FromQuery] int page) => await this.LuckyDipSlots(30 * page, 30, 69);
|
public async Task<IActionResult> CoolSlots
|
||||||
|
(
|
||||||
|
[FromQuery] int pageStart,
|
||||||
|
[FromQuery] int pageSize,
|
||||||
|
[FromQuery] string gameFilterType,
|
||||||
|
[FromQuery] int players,
|
||||||
|
[FromQuery] Boolean move,
|
||||||
|
[FromQuery] int? page = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int _pageStart = pageStart;
|
||||||
|
if (page != null) _pageStart = (int)page * 30;
|
||||||
|
// bit of a better placeholder until we can track average user interaction with /stream endpoint
|
||||||
|
return await ThumbsSlots(_pageStart, Math.Min(pageSize, 30), gameFilterType, players, move, "thisWeek");
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("slots")]
|
[HttpGet("slots")]
|
||||||
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
|
@ -198,5 +212,137 @@ namespace LBPUnion.ProjectLighthouse.Controllers
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("slots/thumbs")]
|
||||||
|
public async Task<IActionResult> ThumbsSlots
|
||||||
|
(
|
||||||
|
[FromQuery] int pageStart,
|
||||||
|
[FromQuery] int pageSize,
|
||||||
|
[FromQuery] string gameFilterType,
|
||||||
|
[FromQuery] int players,
|
||||||
|
[FromQuery] Boolean move,
|
||||||
|
[FromQuery] string? dateFilterType = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Random rand = new();
|
||||||
|
|
||||||
|
IEnumerable<Slot> slots = FilterByRequest(gameFilterType, dateFilterType)
|
||||||
|
.AsEnumerable()
|
||||||
|
.OrderByDescending(s => s.Thumbsup)
|
||||||
|
.ThenBy(_ => rand.Next())
|
||||||
|
.Skip(pageStart - 1)
|
||||||
|
.Take(Math.Min(pageSize, 30));
|
||||||
|
|
||||||
|
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize());
|
||||||
|
|
||||||
|
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "hint_start", pageStart + Math.Min(pageSize, 30)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("slots/mostUniquePlays")]
|
||||||
|
public async Task<IActionResult> MostUniquePlaysSlots
|
||||||
|
(
|
||||||
|
[FromQuery] int pageStart,
|
||||||
|
[FromQuery] int pageSize,
|
||||||
|
[FromQuery] string gameFilterType,
|
||||||
|
[FromQuery] int players,
|
||||||
|
[FromQuery] Boolean move,
|
||||||
|
[FromQuery] string? dateFilterType = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Random rand = new();
|
||||||
|
|
||||||
|
IEnumerable<Slot> slots = FilterByRequest(gameFilterType, dateFilterType)
|
||||||
|
.AsEnumerable()
|
||||||
|
.OrderByDescending
|
||||||
|
(
|
||||||
|
s =>
|
||||||
|
{
|
||||||
|
// probably not the best way to do this?
|
||||||
|
return GetGameFilter(gameFilterType) switch
|
||||||
|
{
|
||||||
|
GameVersion.LittleBigPlanet1 => s.PlaysLBP1Unique,
|
||||||
|
GameVersion.LittleBigPlanet2 => s.PlaysLBP2Unique,
|
||||||
|
GameVersion.LittleBigPlanet3 => s.PlaysLBP3Unique,
|
||||||
|
GameVersion.LittleBigPlanetVita => s.PlaysLBPVitaUnique,
|
||||||
|
_ => s.PlaysUnique,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ThenBy(_ => rand.Next())
|
||||||
|
.Skip(pageStart - 1)
|
||||||
|
.Take(Math.Min(pageSize, 30));
|
||||||
|
|
||||||
|
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize());
|
||||||
|
|
||||||
|
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "hint_start", pageStart + Math.Min(pageSize, 30)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("slots/mostHearted")]
|
||||||
|
public async Task<IActionResult> MostHeartedSlots
|
||||||
|
(
|
||||||
|
[FromQuery] int pageStart,
|
||||||
|
[FromQuery] int pageSize,
|
||||||
|
[FromQuery] string gameFilterType,
|
||||||
|
[FromQuery] int players,
|
||||||
|
[FromQuery] Boolean move,
|
||||||
|
[FromQuery] string? dateFilterType = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Random rand = new();
|
||||||
|
|
||||||
|
IEnumerable<Slot> slots = FilterByRequest(gameFilterType, dateFilterType)
|
||||||
|
.AsEnumerable()
|
||||||
|
.OrderByDescending(s => s.Hearts)
|
||||||
|
.ThenBy(_ => rand.Next())
|
||||||
|
.Skip(pageStart - 1)
|
||||||
|
.Take(Math.Min(pageSize, 30));
|
||||||
|
|
||||||
|
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize());
|
||||||
|
|
||||||
|
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "hint_start", pageStart + Math.Min(pageSize, 30)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameVersion GetGameFilter(string gameFilterType)
|
||||||
|
{
|
||||||
|
return gameFilterType switch
|
||||||
|
{
|
||||||
|
"lbp1" => GameVersion.LittleBigPlanet1,
|
||||||
|
"lbp2" => GameVersion.LittleBigPlanet2,
|
||||||
|
"lbp3" => GameVersion.LittleBigPlanet3,
|
||||||
|
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
||||||
|
_ => GameVersion.Unknown,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQueryable<Slot> FilterByRequest(string gameFilterType, string? dateFilterType)
|
||||||
|
{
|
||||||
|
string _dateFilterType = dateFilterType ?? "";
|
||||||
|
|
||||||
|
long oldestTime = _dateFilterType switch
|
||||||
|
{
|
||||||
|
"thisWeek" => DateTimeOffset.Now.AddDays(-7).ToUnixTimeMilliseconds(),
|
||||||
|
"thisMonth" => DateTimeOffset.Now.AddDays(-31).ToUnixTimeMilliseconds(),
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
GameVersion gameVersion = GetGameFilter(gameFilterType);
|
||||||
|
|
||||||
|
IQueryable<Slot> whereSlots;
|
||||||
|
|
||||||
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
|
if (gameFilterType == "both")
|
||||||
|
{
|
||||||
|
// Get game versions less than the current version
|
||||||
|
// Needs support for LBP3 ("both" = LBP1+2)
|
||||||
|
whereSlots = this.database.Slots.Where(s => s.GameVersion <= gameVersion && s.FirstUploaded >= oldestTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get game versions exactly equal to gamefiltertype
|
||||||
|
whereSlots = this.database.Slots.Where(s => s.GameVersion == gameVersion && s.FirstUploaded >= oldestTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return whereSlots.Include(s => s.Creator).Include(s => s.Location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("teamPick")]
|
[HttpGet("teamPick")]
|
||||||
public async Task<IActionResult> TeamPick([FromRoute] int id)
|
public async Task<IActionResult> TeamPick([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
@ -35,7 +35,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("removeTeamPick")]
|
[HttpGet("removeTeamPick")]
|
||||||
public async Task<IActionResult> RemoveTeamPick([FromRoute] int id)
|
public async Task<IActionResult> RemoveTeamPick([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
@ -51,7 +51,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("delete")]
|
[HttpGet("delete")]
|
||||||
public async Task<IActionResult> DeleteLevel([FromRoute] int id)
|
public async Task<IActionResult> DeleteLevel([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#nullable enable
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin
|
||||||
|
{
|
||||||
|
[ApiController]
|
||||||
|
[Route("admin/user/{id:int}")]
|
||||||
|
public class AdminUserController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly Database database;
|
||||||
|
|
||||||
|
public AdminUserController(Database database)
|
||||||
|
{
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("unban")]
|
||||||
|
public async Task<IActionResult> UnbanUser([FromRoute] int id)
|
||||||
|
{
|
||||||
|
User? user = this.database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
User? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
|
;
|
||||||
|
if (targetedUser == null) return this.NotFound();
|
||||||
|
|
||||||
|
targetedUser.Banned = false;
|
||||||
|
targetedUser.BannedReason = null;
|
||||||
|
|
||||||
|
await this.database.SaveChangesAsync();
|
||||||
|
return this.Redirect($"/user/{targetedUser.UserId}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,11 +11,11 @@ namespace LBPUnion.ProjectLighthouse.Maintenance.Commands
|
||||||
public class DeleteUserCommand : ICommand
|
public class DeleteUserCommand : ICommand
|
||||||
{
|
{
|
||||||
private readonly Database database = new();
|
private readonly Database database = new();
|
||||||
public string Name() => "Delete/Ban User";
|
public string Name() => "Delete User";
|
||||||
public string[] Aliases()
|
public string[] Aliases()
|
||||||
=> new[]
|
=> new[]
|
||||||
{
|
{
|
||||||
"deleteUser", "wipeUser", "banUser",
|
"deleteUser", "wipeUser",
|
||||||
};
|
};
|
||||||
public string Arguments() => "<username/userId>";
|
public string Arguments() => "<username/userId>";
|
||||||
public int RequiredArgs() => 1;
|
public int RequiredArgs() => 1;
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(Database))]
|
||||||
|
[Migration("20211217000749_AddBannedPropertiesToUser")]
|
||||||
|
public partial class AddBannedPropertiesToUser : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "Banned",
|
||||||
|
table: "Users",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "BannedReason",
|
||||||
|
table: "Users",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Banned",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "BannedReason",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -546,6 +546,12 @@ namespace ProjectLighthouse.Migrations
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("Banned")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("BannedReason")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<string>("Biography")
|
b.Property<string>("Biography")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
|
20
ProjectLighthouse/Pages/Admin/AdminBanUserPage.cshtml
Normal file
20
ProjectLighthouse/Pages/Admin/AdminBanUserPage.cshtml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
@page "/admin/user/{id:int}/ban"
|
||||||
|
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminBanUserPage
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "Layouts/BaseLayout";
|
||||||
|
Model.Title = "Ban " + Model.TargetedUser!.Username + "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>Are you sure you want to ban this user?</p>
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
|
|
||||||
|
<div class="ui left labeled input">
|
||||||
|
<label for="text" class="ui blue label">Reason: </label>
|
||||||
|
<input type="text" name="reason" id="text">
|
||||||
|
</div><br><br>
|
||||||
|
|
||||||
|
<input type="submit" value="Yes, ban @Model.TargetedUser.Username!" id="submit" class="ui red button"><br>
|
||||||
|
</form>
|
49
ProjectLighthouse/Pages/Admin/AdminBanUserPage.cshtml.cs
Normal file
49
ProjectLighthouse/Pages/Admin/AdminBanUserPage.cshtml.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#nullable enable
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Pages.Admin;
|
||||||
|
|
||||||
|
public class AdminBanUserPage : BaseLayout
|
||||||
|
{
|
||||||
|
public AdminBanUserPage(Database database) : base(database)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public User? TargetedUser;
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet([FromRoute] int id)
|
||||||
|
{
|
||||||
|
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
|
if (this.TargetedUser == null) return this.NotFound();
|
||||||
|
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnPost([FromRoute] int id, string reason)
|
||||||
|
{
|
||||||
|
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
|
if (this.TargetedUser == null) return this.NotFound();
|
||||||
|
|
||||||
|
this.TargetedUser.Banned = true;
|
||||||
|
this.TargetedUser.BannedReason = reason;
|
||||||
|
|
||||||
|
// invalidate all currently active gametokens
|
||||||
|
this.Database.GameTokens.RemoveRange(this.Database.GameTokens.Where(t => t.UserId == this.TargetedUser.UserId));
|
||||||
|
|
||||||
|
// invalidate all currently active webtokens
|
||||||
|
this.Database.WebTokens.RemoveRange(this.Database.WebTokens.Where(t => t.UserId == this.TargetedUser.UserId));
|
||||||
|
|
||||||
|
await this.Database.SaveChangesAsync();
|
||||||
|
return this.Redirect($"/user/{this.TargetedUser.UserId}");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
@page "/admin"
|
@page "/admin"
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers
|
@using LBPUnion.ProjectLighthouse.Helpers
|
||||||
@using LBPUnion.ProjectLighthouse.Maintenance
|
@using LBPUnion.ProjectLighthouse.Maintenance
|
||||||
@model LBPUnion.ProjectLighthouse.Pages.AdminPanelPage
|
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminPanelPage
|
||||||
|
|
||||||
@{
|
@{
|
||||||
Layout = "Layouts/BaseLayout";
|
Layout = "Layouts/BaseLayout";
|
|
@ -7,7 +7,7 @@ using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Pages
|
namespace LBPUnion.ProjectLighthouse.Pages.Admin
|
||||||
{
|
{
|
||||||
public class AdminPanelPage : BaseLayout
|
public class AdminPanelPage : BaseLayout
|
||||||
{
|
{
|
|
@ -24,7 +24,7 @@
|
||||||
<div class="header">
|
<div class="header">
|
||||||
Uh oh!
|
Uh oh!
|
||||||
</div>
|
</div>
|
||||||
<p>@Model.Error</p>
|
<p style="white-space: pre-line">@Model.Error</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Kettu;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -36,16 +38,25 @@ namespace LBPUnion.ProjectLighthouse.Pages
|
||||||
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
Logger.Log($"User {username} failed to login on web due to invalid username", LoggerLevelLogin.Instance);
|
||||||
this.Error = "The username or password you entered is invalid.";
|
this.Error = "The username or password you entered is invalid.";
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BCrypt.Net.BCrypt.Verify(password, user.Password))
|
if (!BCrypt.Net.BCrypt.Verify(password, user.Password))
|
||||||
{
|
{
|
||||||
|
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", LoggerLevelLogin.Instance);
|
||||||
this.Error = "The username or password you entered is invalid.";
|
this.Error = "The username or password you entered is invalid.";
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (user.Banned)
|
||||||
|
{
|
||||||
|
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", LoggerLevelLogin.Instance);
|
||||||
|
this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason;
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
|
||||||
WebToken webToken = new()
|
WebToken webToken = new()
|
||||||
{
|
{
|
||||||
UserId = user.UserId,
|
UserId = user.UserId,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Model.Title = "Password Reset Required";
|
Model.Title = "Password Reset Required";
|
||||||
}
|
}
|
||||||
|
|
||||||
<p>An admin has deemed it necessary that you reset your password. Please do so.</p>
|
<p>An administrator has deemed it necessary that you reset your password. Please do so.</p>
|
||||||
|
|
||||||
<a href="/passwordReset">
|
<a href="/passwordReset">
|
||||||
<div class="ui blue button">Reset Password</div>
|
<div class="ui blue button">Reset Password</div>
|
||||||
|
|
|
@ -14,12 +14,34 @@
|
||||||
Model.Description = Model.ProfileUser!.Biography;
|
Model.Description = Model.ProfileUser!.Biography;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@if (Model.ProfileUser.Banned)
|
||||||
|
{
|
||||||
|
<div class="ui inverted red segment">
|
||||||
|
<p>
|
||||||
|
<b>User is currently banned!</b>
|
||||||
|
</p>
|
||||||
|
@if (Model.User != null && Model.User.IsAdmin)
|
||||||
|
{
|
||||||
|
<p>Reason: @Model.ProfileUser.BannedReason</p>
|
||||||
|
<a class="ui inverted button" href="/admin/user/@Model.ProfileUser.UserId/unban">
|
||||||
|
<i class="ban icon"></i>
|
||||||
|
<span>Unban User</span>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>For shame...</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
<h1>@Model.Title</h1>
|
<h1>@Model.Title</h1>
|
||||||
<p>
|
<p>
|
||||||
<i>@Model.ProfileUser!.Status</i>
|
<i>@Model.ProfileUser!.Status</i>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="statsUnderTitle">
|
<div class="statsUnderTitle">
|
||||||
<i class="pink heart icon" title="Hearts"></i> <span>@Model.ProfileUser.Hearts</span>
|
<i class="pink heart icon" title="Hearts"></i> <span>@Model.ProfileUser.Hearts</span>
|
||||||
<i class="blue comment icon" title="Comments"></i> <span>@Model.ProfileUser.Comments</span>
|
<i class="blue comment icon" title="Comments"></i> <span>@Model.ProfileUser.Comments</span>
|
||||||
|
@ -53,6 +75,13 @@
|
||||||
<span>Reset Password</span>
|
<span>Reset Password</span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
@if (Model.User != null && Model.User.IsAdmin && !Model.ProfileUser.Banned)
|
||||||
|
{
|
||||||
|
<a class="ui red button" href="/admin/user/@Model.ProfileUser.UserId/ban">
|
||||||
|
<i class="ban icon"></i>
|
||||||
|
<span>Ban User</span>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="eight wide column">
|
<div class="eight wide column">
|
||||||
<div class="ui blue segment">
|
<div class="ui blue segment">
|
||||||
|
|
|
@ -87,11 +87,34 @@ namespace LBPUnion.ProjectLighthouse
|
||||||
Stopwatch requestStopwatch = new();
|
Stopwatch requestStopwatch = new();
|
||||||
requestStopwatch.Start();
|
requestStopwatch.Start();
|
||||||
|
|
||||||
|
context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging
|
||||||
|
|
||||||
// Log all headers.
|
// Log all headers.
|
||||||
// foreach (KeyValuePair<string, StringValues> header in context.Request.Headers) Logger.Log($"{header.Key}: {header.Value}");
|
// foreach (KeyValuePair<string, StringValues> header in context.Request.Headers) Logger.Log($"{header.Key}: {header.Value}");
|
||||||
|
|
||||||
context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging
|
await next(context); // Handle the request so we can get the status code from it
|
||||||
|
|
||||||
|
requestStopwatch.Stop();
|
||||||
|
|
||||||
|
Logger.Log
|
||||||
|
(
|
||||||
|
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
||||||
|
LoggerLevelHttp.Instance
|
||||||
|
);
|
||||||
|
|
||||||
|
if (context.Request.Method == "POST")
|
||||||
|
{
|
||||||
|
context.Request.Body.Position = 0;
|
||||||
|
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Digest check
|
||||||
|
app.Use
|
||||||
|
(
|
||||||
|
async (context, next) =>
|
||||||
|
{
|
||||||
// Client digest check.
|
// Client digest check.
|
||||||
if (!context.Request.Cookies.TryGetValue("MM_AUTH", out string authCookie)) authCookie = string.Empty;
|
if (!context.Request.Cookies.TryGetValue("MM_AUTH", out string authCookie)) authCookie = string.Empty;
|
||||||
string digestPath = context.Request.Path;
|
string digestPath = context.Request.Path;
|
||||||
|
@ -119,7 +142,7 @@ namespace LBPUnion.ProjectLighthouse
|
||||||
Stream oldResponseStream = context.Response.Body;
|
Stream oldResponseStream = context.Response.Body;
|
||||||
context.Response.Body = responseBuffer;
|
context.Response.Body = responseBuffer;
|
||||||
|
|
||||||
await next(); // Handle the request so we can get the status code from it
|
await next(context); // Handle the request so we can get the server digest hash
|
||||||
|
|
||||||
// Compute the server digest hash.
|
// Compute the server digest hash.
|
||||||
if (computeDigests)
|
if (computeDigests)
|
||||||
|
@ -138,7 +161,13 @@ namespace LBPUnion.ProjectLighthouse
|
||||||
responseBuffer.Position = 0;
|
responseBuffer.Position = 0;
|
||||||
await responseBuffer.CopyToAsync(oldResponseStream);
|
await responseBuffer.CopyToAsync(oldResponseStream);
|
||||||
context.Response.Body = oldResponseStream;
|
context.Response.Body = oldResponseStream;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
app.Use
|
||||||
|
(
|
||||||
|
async (context, next) =>
|
||||||
|
{
|
||||||
#nullable enable
|
#nullable enable
|
||||||
// Log LastContact for LBP1. This is done on LBP2/3/V on a Match request.
|
// Log LastContact for LBP1. This is done on LBP2/3/V on a Match request.
|
||||||
if (context.Request.Path.ToString().StartsWith("/LITTLEBIGPLANETPS3_XML"))
|
if (context.Request.Path.ToString().StartsWith("/LITTLEBIGPLANETPS3_XML"))
|
||||||
|
@ -153,19 +182,7 @@ namespace LBPUnion.ProjectLighthouse
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
requestStopwatch.Stop();
|
await next(context);
|
||||||
|
|
||||||
Logger.Log
|
|
||||||
(
|
|
||||||
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
|
||||||
LoggerLevelHttp.Instance
|
|
||||||
);
|
|
||||||
|
|
||||||
if (context.Request.Method == "POST")
|
|
||||||
{
|
|
||||||
context.Request.Body.Position = 0;
|
|
||||||
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings
|
||||||
public class ServerSettings
|
public class ServerSettings
|
||||||
{
|
{
|
||||||
|
|
||||||
public const int CurrentConfigVersion = 13; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
|
public const int CurrentConfigVersion = 14; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
|
||||||
static ServerSettings()
|
static ServerSettings()
|
||||||
{
|
{
|
||||||
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
||||||
|
@ -74,6 +74,12 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings
|
||||||
|
|
||||||
public string EulaText { get; set; } = "";
|
public string EulaText { get; set; } = "";
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
|
public string AnnounceText { get; set; } = "You are now logged in as %user.";
|
||||||
|
#else
|
||||||
|
public string AnnounceText { get; set; } = "You are now logged in as %user (id: %id).";
|
||||||
|
#endif
|
||||||
|
|
||||||
public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse";
|
||||||
|
|
||||||
public string ExternalUrl { get; set; } = "http://localhost:10060";
|
public string ExternalUrl { get; set; } = "http://localhost:10060";
|
||||||
|
|
|
@ -125,6 +125,10 @@ namespace LBPUnion.ProjectLighthouse.Types
|
||||||
}
|
}
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
public bool Banned { get; set; }
|
||||||
|
|
||||||
|
public string BannedReason { get; set; }
|
||||||
|
|
||||||
public string Serialize(GameVersion gameVersion = GameVersion.LittleBigPlanet1)
|
public string Serialize(GameVersion gameVersion = GameVersion.LittleBigPlanet1)
|
||||||
{
|
{
|
||||||
string user = LbpSerializer.TaggedStringElement("npHandle", this.Username, "icon", this.IconHash) +
|
string user = LbpSerializer.TaggedStringElement("npHandle", this.Username, "icon", this.IconHash) +
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# Project Lighthouse
|
# Project Lighthouse
|
||||||
|
|
||||||
Project Lighthouse is an umbrella project for all work to investigate and develop private servers for LittleBigPlanet.
|
Project Lighthouse is a clean-room, open-source custom server for LittleBigPlanet. This is a project conducted by the [LBP Union Ministry of Technology Research and Development team.](https://www.lbpunion.com/technology) For concerns and inquiries about the project, please [contact us here.](https://www.lbpunion.com/contact) For general questions and discussion about Project Lighthouse, please see the [megathread](https://www.lbpunion.com/forum/union-hall/project-lighthouse-littlebigplanet-private-servers-megathread) on our forum.
|
||||||
This project is the main server component that LittleBigPlanet games connect to.
|
|
||||||
|
|
||||||
## WARNING!
|
## WARNING!
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue