Merge master into ..i'm not typing that.

This commit is contained in:
jvyden 2022-06-10 03:57:00 -04:00
commit b3b5354c68
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
334 changed files with 5045 additions and 2956 deletions

View file

@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "6.0.0",
"version": "6.0.5",
"commands": [
"dotnet-ef"
]

View file

@ -14,7 +14,7 @@ jobs:
matrix:
os:
- { prettyName: Linux, fullName: ubuntu-latest, database: true, webTest: true }
timeout-minutes: 10
timeout-minutes: 5
env:
DB_DATABASE: lighthouse
DB_USER: root
@ -44,16 +44,16 @@ jobs:
- name: Run tests on ProjectLighthouse.Tests
continue-on-error: true
run: dotnet test --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-Tests.trx" ProjectLighthouse.Tests
run: dotnet test --no-build --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
run: dotnet test --no-build --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
run: dotnet test --no-build --logger "trx;LogFileName=${{github.workspace}}/TestResults-${{matrix.os.prettyName}}-WebsiteTests.trx" ProjectLighthouse.Tests.WebsiteTests
# Attempt to upload results even if test fails.
# https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always

1
.gitignore vendored
View file

@ -23,6 +23,7 @@ png/
/ProjectLighthouse/r/*
/ProjectLighthouse/logs/*
lighthouse.config.json
lighthouse.yml
gitBranch.txt
gitVersion.txt
gitRemotes.txt

View file

@ -3,16 +3,20 @@
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes>
<Path>.config/dotnet-tools.json</Path>
<Path>.github</Path>
<Path>.gitignore</Path>
<Path>.idea</Path>
<Path>CONTRIBUTING.md</Path>
<Path>DatabaseMigrations</Path>
<Path>LICENSE</Path>
<Path>ProjectLighthouse.sln.DotSettings</Path>
<Path>ProjectLighthouse.sln.DotSettings.user</Path>
<Path>README.md</Path>
<Path>create-migration.sh</Path>
<Path>docker-compose.yml</Path>
<Path>global.json</Path>
<Path>scripts-and-tools</Path>
</explicitIncludes>
<explicitExcludes>
<Path>.idea/.idea.ProjectLighthouse/.idea/workspace.xml</Path>

View file

@ -2,6 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/ProjectLighthouse/Fomantic" vcs="Git" />
</component>
</project>

View file

@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Development Database" type="docker-deploy" factoryName="docker-compose.yml"
<configuration default="false" name="Development Databases" type="docker-deploy" factoryName="docker-compose.yml"
server-name="Docker">
<deployment type="docker-compose.yml">
<settings>
@ -7,6 +7,7 @@
<option name="sourceFilePath" value="docker-compose.yml"/>
</settings>
</deployment>
<EXTENSION ID="com.jetbrains.rider.docker.debug" isFastModeEnabled="true" isPublishEnabled="true"/>
<method v="2"/>
</configuration>
</component>

View file

@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lighthouse API" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.API/bin/Debug/net6.0/LBPUnion.ProjectLighthouse.Servers.API" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/ProjectLighthouse" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.API/ProjectLighthouse.Servers.API.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="0" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Development Databases" run_configuration_type="docker-deploy" />
<option name="Build" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lighthouse Gameserver" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.GameServer/bin/Debug/net6.0/LBPUnion.ProjectLighthouse.Servers.GameServer" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/ProjectLighthouse" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.GameServer/ProjectLighthouse.Servers.GameServer.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="0" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Development Databases" run_configuration_type="docker-deploy" />
<option name="Build" />
</method>
</configuration>
</component>

View file

@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lighthouse Website" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.Website/bin/Debug/net6.0/LBPUnion.ProjectLighthouse.Servers.Website" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/ProjectLighthouse" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/ProjectLighthouse.Servers.Website/ProjectLighthouse.Servers.Website.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="0" />
<option name="PROJECT_KIND" value="DotNetCore" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Development Databases" run_configuration_type="docker-deploy" />
<option name="Build" />
</method>
</configuration>
</component>

21
.run/Lighthouse.run.xml Normal file
View file

@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Lighthouse" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/ProjectLighthouse/bin/Debug/net6.0/LBPUnion.ProjectLighthouse" />
<option name="PROGRAM_PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/ProjectLighthouse" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<option name="USE_MONO" value="0" />
<option name="RUNTIME_ARGUMENTS" value="" />
<option name="PROJECT_PATH" value="$PROJECT_DIR$/ProjectLighthouse/ProjectLighthouse.csproj" />
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
<option name="PROJECT_KIND" value="Unloaded" />
<option name="PROJECT_TFM" value="net6.0" />
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Development Databases" run_configuration_type="docker-deploy" />
<option name="Build" />
</method>
</configuration>
</component>

View file

@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
#nullable enable
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.Servers.API.Responses;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Api;
namespace LBPUnion.ProjectLighthouse.Servers.API.Controllers;
/// <summary>
/// A collection of endpoints relating to slots.

View file

@ -1,11 +1,9 @@
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Servers.API.Responses;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Api;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.Api;
namespace LBPUnion.ProjectLighthouse.Servers.API.Controllers;
/// <summary>
/// A collection of endpoints relating to statistics.

View file

@ -1,14 +1,12 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
// ReSharper disable RouteTemplates.ActionRoutePrefixCanBeExtractedToControllerRoute
namespace LBPUnion.ProjectLighthouse.Controllers.Api;
namespace LBPUnion.ProjectLighthouse.Servers.API.Controllers;
/// <summary>
/// A collection of endpoints relating to users.
@ -50,7 +48,7 @@ public class UserEndpoints : ApiEndpointController
[HttpGet("user/{id:int}/status")]
[ProducesResponseType(typeof(UserStatus), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> GetUserStatus(int id)
public IActionResult GetUserStatus(int id)
{
UserStatus userStatus = new(this.database, id);

View file

@ -0,0 +1,36 @@
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
using LBPUnion.ProjectLighthouse.Servers.API.Startup;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace LBPUnion.ProjectLighthouse.Servers.API;
public static class Program
{
public static void Main(string[] args)
{
StartupTasks.Run(args, ServerType.Api);
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults
(
webBuilder =>
{
webBuilder.UseStartup<ApiStartup>();
webBuilder.UseUrls(ServerConfiguration.Instance.ApiListenUrl);
}
)
.ConfigureLogging
(
logging =>
{
logging.ClearProviders();
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
}
);
}

View file

@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LBPUnion.ProjectLighthouse.Servers.API</AssemblyName>
<RootNamespace>LBPUnion.ProjectLighthouse.Servers.API</RootNamespace>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
</ItemGroup>
<ItemGroup>
<None Remove="gitVersion.txt"/>
<EmbeddedResource Include="gitVersion.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitBranch.txt"/>
<EmbeddedResource Include="gitBranch.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitRemotes.txt"/>
<EmbeddedResource Include="gitRemotes.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitUnpushed.txt"/>
<EmbeddedResource Include="gitUnpushed.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 &gt; &quot;$(ProjectDir)/gitVersion.txt&quot;"/>
<Exec Command="git branch --show-current &gt; &quot;$(ProjectDir)/gitBranch.txt&quot;"/>
<Exec Command="git remote -v &gt; &quot;$(ProjectDir)/gitRemotes.txt&quot;"/>
<Exec Command="git log --branches --not --remotes --oneline &gt; &quot;$(ProjectDir)/gitUnpushed.txt&quot;"/>
</Target>
</Project>

View file

@ -1,4 +1,8 @@
namespace LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Types;
namespace LBPUnion.ProjectLighthouse.Servers.API.Responses;
public struct MinimalSlot
{

View file

@ -1,4 +1,4 @@
namespace LBPUnion.ProjectLighthouse.Types.Api;
namespace LBPUnion.ProjectLighthouse.Servers.API.Responses;
public class StatisticsResponse
{

View file

@ -0,0 +1,74 @@
using LBPUnion.ProjectLighthouse.Middlewares;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.OpenApi.Models;
namespace LBPUnion.ProjectLighthouse.Servers.API.Startup;
public class ApiStartup
{
public ApiStartup(IConfiguration configuration)
{
this.Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddMvc
(
options =>
{
options.OutputFormatters.Add(new JsonOutputFormatter());
}
);
services.AddDbContext<Database>();
services.AddSwaggerGen
(
c =>
{
// Give swagger the name and version of our project
c.SwaggerDoc
(
"v1",
new OpenApiInfo
{
Title = "Project Lighthouse API",
Version = "v1",
}
);
// Filter out endpoints not in /api/v1
c.DocumentFilter<SwaggerFilter>();
// Add XMLDoc to swagger
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "LBPUnion.ProjectLighthouse.Servers.API.xml"));
}
);
}
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
#if DEBUG
app.UseDeveloperExceptionPage();
#endif
app.UseSwagger();
app.UseSwaggerUI
(
c =>
{
c.SwaggerEndpoint("v1/swagger.json", "Project Lighthouse API");
}
);
app.UseMiddleware<RequestLogMiddleware>();
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
}
}

View file

@ -0,0 +1,15 @@
using LBPUnion.ProjectLighthouse.Middlewares;
namespace LBPUnion.ProjectLighthouse.Servers.API.Startup;
public class ApiTestStartup : ApiStartup
{
public ApiTestStartup(IConfiguration configuration) : base(configuration)
{}
public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<FakeRemoteIPAddressMiddleware>();
base.Configure(app, env);
}
}

View file

@ -1,10 +1,16 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace LBPUnion.ProjectLighthouse.Helpers;
namespace LBPUnion.ProjectLighthouse.Servers.API;
/// <summary>
/// <para>
/// A filter for the swagger documentation endpoint.
/// </para>
/// <para>
/// Makes sure that only endpoints under <c>/api/v1</c> show up.
/// </para>
/// </summary>
public class SwaggerFilter : IDocumentFilter
{
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View file

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View file

@ -1,12 +1,11 @@
#nullable enable
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -25,7 +24,7 @@ public class ClientConfigurationController : ControllerBase
public async Task<IActionResult> NetworkSettings()
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return null;
if (token == null) return this.StatusCode(403, "");
HostString hostname = this.Request.Host;
return this.Ok
@ -33,7 +32,7 @@ public class ClientConfigurationController : ControllerBase
"ProbabilityOfPacketDelay 0.0\nMinPacketDelayFrames 0\nMaxPacketDelayFrames 3\nProbabilityOfPacketDrop 0.0\nEnableFakeConditionsForLoopback true\nNumberOfFramesPredictionAllowedForNonLocalPlayer 1000\nEnablePrediction true\nMinPredictedFrames 0\nMaxPredictedFrames 10\nAllowGameRendCameraSplit true\nFramesBeforeAgressiveCatchup 30\nPredictionPadSides 200\nPredictionPadTop 200\nPredictionPadBottom 200\nShowErrorNumbers true\nAllowModeratedLevels false\nAllowModeratedPoppetItems false\nTIMEOUT_WAIT_FOR_JOIN_RESPONSE_FROM_PREV_PARTY_HOST 50.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_HOST 30.0\nTIMEOUT_WAIT_FOR_CHANGE_LEVEL_PARTY_MEMBER 45.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN_FRIEND 15.0\nTIMEOUT_WAIT_FOR_CONNECTION_FROM_HOST 30.0\nTIMEOUT_WAIT_FOR_ROOM_ID_TO_JOIN 60.0\nTIMEOUT_WAIT_FOR_GET_NUM_PLAYERS_ONLINE 60.0\nTIMEOUT_WAIT_FOR_SIGNALLING_CONNECTIONS 120.0\nTIMEOUT_WAIT_FOR_PARTY_DATA 60.0\nTIME_TO_WAIT_FOR_LEAVE_MESSAGE_TO_COME_BACK 20.0\nTIME_TO_WAIT_FOR_FOLLOWING_REQUESTS_TO_ARRIVE 30.0\nTIMEOUT_WAIT_FOR_FINISHED_MIGRATING_HOST 30.0\nTIMEOUT_WAIT_FOR_PARTY_LEADER_FINISH_JOINING 45.0\nTIMEOUT_WAIT_FOR_QUICKPLAY_LEVEL 60.0\nTIMEOUT_WAIT_FOR_PLAYERS_TO_JOIN 30.0\nTIMEOUT_WAIT_FOR_DIVE_IN_PLAYERS 240.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 60.0\nTIMEOUT_DIVE_IN_TOTAL 300.0\nTIMEOUT_WAIT_FOR_SOCKET_CONNECTION 120.0\nTIMEOUT_WAIT_FOR_REQUEST_RESOURCE_MESSAGE 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_GET_RESOURCE_LIST 120.0\nTIMEOUT_WAIT_FOR_CLIENT_TO_LOAD_RESOURCES 120.0\nTIMEOUT_WAIT_FOR_LOCAL_CLIENT_TO_SAVE_GAME_STATE 30.0\nTIMEOUT_WAIT_FOR_ADD_PLAYERS_TO_TAKE 30.0\nTIMEOUT_WAIT_FOR_UPDATE_FROM_CLIENT 90.0\nTIMEOUT_WAIT_FOR_HOST_TO_GET_RESOURCE_LIST 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_SAVE_GAME_STATE 60.0\nTIMEOUT_WAIT_FOR_HOST_TO_ADD_US 30.0\nTIMEOUT_WAIT_FOR_UPDATE 60.0\nTIMEOUT_WAIT_FOR_REQUEST_JOIN 50.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_PRESENCE 60.0\nTIMEOUT_WAIT_FOR_AUTOJOIN_CONNECTION 120.0\nSECONDS_BETWEEN_PINS_AWARDED_UPLOADS 300.0\nEnableKeepAlive true\nAllowVoIPRecordingPlayback true\nOverheatingThresholdDisallowMidgameJoin 0.95\nMaxCatchupFrames 3\nMaxLagBeforeShowLoading 23\nMinLagBeforeHideLoading 30\nLagImprovementInflectionPoint -1.0\nFlickerThreshold 2.0\nClosedDemo2014Version 1\nClosedDemo2014Expired false\nEnablePlayedFilter true\nEnableCommunityDecorations true\nGameStateUpdateRate 10.0\nGameStateUpdateRateWithConsumers 1.0\nDisableDLCPublishCheck false\nEnableDiveIn true\nEnableHackChecks false\nAllowOnlineCreate true" +
$"TelemetryServer {hostname}\n" +
$"CDNHostName {hostname}\n" +
$"ShowLevelBoos {ServerSettings.Instance.BooingEnabled.ToString().ToLower()}\n"
$"ShowLevelBoos {ServerConfiguration.Instance.UserGeneratedContentLimits.BooingEnabled.ToString().ToLower()}\n"
);
}

View file

@ -1,19 +1,15 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Profiles;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]

View file

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]

View file

@ -1,17 +1,16 @@
#nullable enable
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.StorableLists;
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -57,14 +56,13 @@ public class FriendsController : ControllerBase
blockedUsers.Add(blockedUser.UserId);
}
if (FriendHelper.FriendIdsByUserId.ContainsKey(user.UserId))
{
FriendHelper.FriendIdsByUserId.Remove(user.UserId);
FriendHelper.BlockedIdsByUserId.Remove(user.UserId);
}
UserFriendData? friendStore = UserFriendStore.GetUserFriendData(user.UserId);
if (friendStore == null) friendStore = UserFriendStore.CreateUserFriendData(user.UserId);
FriendHelper.FriendIdsByUserId.Add(user.UserId, friends.Select(u => u.UserId).ToArray());
FriendHelper.BlockedIdsByUserId.Add(user.UserId, blockedUsers.ToArray());
friendStore.FriendIds = friends.Select(u => u.UserId).ToList();
friendStore.BlockedIds = blockedUsers;
UserFriendStore.UpdateFriendData(friendStore);
string friendsSerialized = friends.Aggregate(string.Empty, (current, user1) => current + LbpSerializer.StringElement("npHandle", user1.Username));
@ -82,11 +80,13 @@ public class FriendsController : ControllerBase
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
if (!FriendHelper.FriendIdsByUserId.TryGetValue(user.UserId, out int[]? friendIds) || friendIds == null)
UserFriendData? friendStore = UserFriendStore.GetUserFriendData(user.UserId);
if (friendStore == null)
return this.Ok(LbpSerializer.BlankElement("myFriends"));
string friends = "";
foreach (int friendId in friendIds)
foreach (int friendId in friendStore.FriendIds)
{
User? friend = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == friendId);
if (friend == null) continue;

View file

@ -1,19 +1,17 @@
#nullable enable
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Match.Rooms;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Tickets;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using LBPUnion.ProjectLighthouse.Types.Tickets;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using IOFile = System.IO.File;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/login")]
@ -46,14 +44,14 @@ public class LoginController : ControllerBase
if (npTicket == null)
{
Logger.Log("npTicket was null, rejecting login", LoggerLevelLogin.Instance);
Logger.Warn("npTicket was null, rejecting login", LogArea.Login);
return this.BadRequest();
}
IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress;
if (remoteIpAddress == null)
{
Logger.Log("unable to determine ip, rejecting login", LoggerLevelLogin.Instance);
Logger.Warn("unable to determine ip, rejecting login", LogArea.Login);
return this.StatusCode(403, ""); // 403 probably isnt the best status code for this, but whatever
}
@ -69,7 +67,7 @@ public class LoginController : ControllerBase
token = await this.database.AuthenticateUser(npTicket, ipAddress);
if (token == null)
{
Logger.Log("unable to find/generate a token, rejecting login", LoggerLevelLogin.Instance);
Logger.Warn($"Unable to find/generate a token for username {npTicket.Username}", LogArea.Login);
return this.StatusCode(403, ""); // If not, then 403.
}
}
@ -78,28 +76,12 @@ public class LoginController : ControllerBase
if (user == null || user.Banned)
{
Logger.Log("unable to find a user from a token, rejecting login", LoggerLevelLogin.Instance);
Logger.Error($"Unable to find user {npTicket.Username} from token", LogArea.Login);
return this.StatusCode(403, "");
}
if (ServerSettings.Instance.UseExternalAuth)
if (ServerConfiguration.Instance.Authentication.UseExternalAuth)
{
if (ServerSettings.Instance.BlockDeniedUsers)
{
string ipAddressAndName = $"{token.UserLocation}|{user.Username}";
if (DeniedAuthenticationHelper.RecentlyDenied(ipAddressAndName) || DeniedAuthenticationHelper.GetAttempts(ipAddressAndName) > 3)
{
this.database.AuthenticationAttempts.RemoveRange
(this.database.AuthenticationAttempts.Include(a => a.GameToken).Where(a => a.GameToken.UserId == user.UserId));
DeniedAuthenticationHelper.AddAttempt(ipAddressAndName);
await this.database.SaveChangesAsync();
Logger.Log("too many denied logins, rejecting login", LoggerLevelLogin.Instance);
return this.StatusCode(403, "");
}
}
if (this.database.UserApprovedIpAddresses.Where(a => a.UserId == user.UserId).Select(a => a.IpAddress).Contains(ipAddress))
{
token.Approved = true;
@ -110,7 +92,7 @@ public class LoginController : ControllerBase
{
GameToken = token,
GameTokenId = token.TokenId,
Timestamp = TimestampHelper.Timestamp,
Timestamp = TimeHelper.Timestamp,
IPAddress = ipAddress,
Platform = npTicket.Platform,
};
@ -127,11 +109,11 @@ public class LoginController : ControllerBase
if (!token.Approved)
{
Logger.Log("token unapproved, rejecting login", LoggerLevelLogin.Instance);
Logger.Warn($"Token unapproved for user {user.Username}, rejecting login", LogArea.Login);
return this.StatusCode(403, "");
}
Logger.Log($"Successfully logged in user {user.Username} as {token.GameVersion} client", LoggerLevelLogin.Instance);
Logger.Success($"Successfully logged in user {user.Username} as {token.GameVersion} client", LogArea.Login);
// After this point we are now considering this session as logged in.
// We just logged in with the token. Mark it as used so someone else doesnt try to use it,
@ -141,14 +123,14 @@ public class LoginController : ControllerBase
await this.database.SaveChangesAsync();
// Create a new room on LBP2/3/Vita
if (token.GameVersion != GameVersion.LittleBigPlanet1) RoomHelper.CreateRoom(user, token.GameVersion, token.Platform);
if (token.GameVersion != GameVersion.LittleBigPlanet1) RoomHelper.CreateRoom(user.UserId, token.GameVersion, token.Platform);
return this.Ok
(
new LoginResult
{
AuthTicket = "MM_AUTH=" + token.UserToken,
LbpEnvVer = ServerStatics.ServerName,
ServerBrand = VersionHelper.FullVersion,
}.Serialize()
);
}

View file

@ -1,13 +1,12 @@
#nullable enable
using System;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Matching;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Matching;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]

View file

@ -1,20 +1,18 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Match;
using LBPUnion.ProjectLighthouse.Match.MatchCommands;
using LBPUnion.ProjectLighthouse.Match.Rooms;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Match;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Matching;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Matching;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -48,29 +46,28 @@ public class MatchController : ControllerBase
if (bodyString.Length == 0 || bodyString[0] != '[') return this.BadRequest();
Logger.Log("Received match data: " + bodyString, LoggerLevelMatch.Instance);
Logger.Info("Received match data: " + bodyString, LogArea.Match);
IMatchData? matchData;
IMatchCommand? matchData;
try
{
matchData = MatchHelper.Deserialize(bodyString);
}
catch(Exception e)
{
Logger.Log("Exception while parsing matchData: ", LoggerLevelMatch.Instance);
string[] lines = e.ToDetailedException().Split("\n");
foreach (string line in lines) Logger.Log(line, LoggerLevelMatch.Instance);
Logger.Error("Exception while parsing matchData: ", LogArea.Match);
Logger.Error(e.ToDetailedException(), LogArea.Match);
return this.BadRequest();
}
if (matchData == null)
{
Logger.Log("Could not parse match data: matchData is null", LoggerLevelMatch.Instance);
Logger.Error($"Could not parse match data: {nameof(matchData)} is null", LogArea.Match);
return this.BadRequest();
}
Logger.Log($"Parsed match from {user.Username} (type: {matchData.GetType()})", LoggerLevelMatch.Instance);
Logger.Info($"Parsed match from {user.Username} (type: {matchData.GetType()})", LogArea.Match);
#endregion
@ -81,10 +78,10 @@ public class MatchController : ControllerBase
if (matchData is UpdateMyPlayerData playerData)
{
MatchHelper.SetUserLocation(user.UserId, gameToken.UserLocation);
Room? room = RoomHelper.FindRoomByUser(user, gameToken.GameVersion, gameToken.Platform, true);
Room? room = RoomHelper.FindRoomByUser(user.UserId, gameToken.GameVersion, gameToken.Platform, true);
if (playerData.RoomState != null)
if (room != null && Equals(room.Host, user))
if (room != null && Equals(room.HostId, user.UserId))
room.State = (RoomState)playerData.RoomState;
}
@ -108,12 +105,12 @@ public class MatchController : ControllerBase
if (matchData is CreateRoom createRoom && MatchHelper.UserLocations.Count >= 1)
{
List<User> users = new();
List<int> users = new();
foreach (string playerUsername in createRoom.Players)
{
User? player = await this.database.Users.FirstOrDefaultAsync(u => u.Username == playerUsername);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (player != null) users.Add(player);
if (player != null) users.Add(player.UserId);
else return this.BadRequest();
}
@ -123,7 +120,7 @@ public class MatchController : ControllerBase
if (matchData is UpdatePlayersInRoom updatePlayersInRoom)
{
Room? room = RoomHelper.Rooms.FirstOrDefault(r => r.Host == user);
Room? room = RoomHelper.Rooms.FirstOrDefault(r => r.HostId == user.UserId);
if (room != null)
{
@ -136,7 +133,7 @@ public class MatchController : ControllerBase
else return this.BadRequest();
}
room.Players = users;
room.PlayerIds = users.Select(u => u.UserId).ToList();
RoomHelper.CleanupRooms(null, room);
}
}

View file

@ -1,14 +1,13 @@
#nullable enable
using System.IO;
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -17,6 +16,20 @@ public class MessageController : ControllerBase
{
private readonly Database database;
private const string license = @"
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.";
public MessageController(Database database)
{
this.database = database;
@ -28,7 +41,7 @@ public class MessageController : ControllerBase
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
return this.Ok($"{EulaHelper.License}\n{ServerSettings.Instance.EulaText}");
return this.Ok($"{license}\n{ServerConfiguration.Instance.EulaText}");
}
[HttpGet("announce")]
@ -47,7 +60,7 @@ public class MessageController : ControllerBase
GameToken gameToken = userAndToken.Value.Item2;
#endif
string announceText = ServerSettings.Instance.AnnounceText;
string announceText = ServerConfiguration.Instance.AnnounceText;
announceText = announceText.Replace("%user", user.Username);
announceText = announceText.Replace("%id", user.UserId.ToString());
@ -78,15 +91,15 @@ public class MessageController : ControllerBase
public async Task<IActionResult> Filter()
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string response = await new StreamReader(this.Request.Body).ReadToEndAsync();
string scannedText = CensorHelper.ScanMessage(response);
Logger.Log($"{user.Username}: {response} / {scannedText}", LoggerLevelFilter.Instance);
Logger.Info($"{user.Username}: {response} / {scannedText}", LogArea.Filter);
return this.Ok(scannedText);
}
}

View file

@ -1,14 +1,13 @@
#nullable enable
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Reports;
using Microsoft.AspNetCore.Mvc;
using LBPUnion.ProjectLighthouse.Administration.Reports;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -32,7 +31,7 @@ public class ReportController : ControllerBase
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(GriefReport));
GriefReport? report = (GriefReport?) serializer.Deserialize(new StringReader(bodyString));
GriefReport? report = (GriefReport?)serializer.Deserialize(new StringReader(bodyString));
if (report == null) return this.BadRequest();

View file

@ -1,21 +1,17 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Discord;
using Kettu;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Resources;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Resources;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -35,7 +31,7 @@ public class PhotosController : ControllerBase
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
if (user.PhotosByMe >= ServerSettings.Instance.PhotosQuota) return this.BadRequest();
if (user.PhotosByMe >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
@ -59,7 +55,7 @@ public class PhotosController : ControllerBase
if (photo.Subjects.Count > 4) return this.BadRequest();
if (photo.Timestamp > TimestampHelper.Timestamp) return this.BadRequest();
if (photo.Timestamp > TimeHelper.Timestamp) photo.Timestamp = TimeHelper.Timestamp;
foreach (PhotoSubject subject in photo.Subjects)
{
@ -68,7 +64,7 @@ public class PhotosController : ControllerBase
if (subject.User == null) continue;
subject.UserId = subject.User.UserId;
Logger.Log($"Adding PhotoSubject (userid {subject.UserId}) to db", LoggerLevelPhotos.Instance);
Logger.Debug($"Adding PhotoSubject (userid {subject.UserId}) to db", LogArea.Photos);
this.database.PhotoSubjects.Add(subject);
}
@ -88,7 +84,7 @@ public class PhotosController : ControllerBase
// photo.Slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId);
Logger.Log($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", LoggerLevelPhotos.Instance);
Logger.Debug($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", LogArea.Photos);
this.database.Photos.Add(photo);
@ -100,7 +96,7 @@ public class PhotosController : ControllerBase
{
Title = "New photo uploaded!",
Description = $"{user.Username} uploaded a new photo.",
ImageUrl = $"{ServerSettings.Instance.ExternalUrl}/gameAssets/{photo.LargeHash}",
ImageUrl = $"{ServerConfiguration.Instance.ExternalUrl}/gameAssets/{photo.LargeHash}",
Color = WebhookHelper.UnionColor,
}
);

View file

@ -1,25 +1,30 @@
#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Buffers;
using System.IO.Pipelines;
using System.Xml.Serialization;
using Kettu;
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Files;
using Microsoft.AspNetCore.Mvc;
using IOFile = System.IO.File;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Resources;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Resources;
[ApiController]
[Produces("text/xml")]
[Route("LITTLEBIGPLANETPS3_XML")]
public class ResourcesController : ControllerBase
{
private readonly Database database;
public ResourcesController(Database database)
{
this.database = database;
}
[HttpPost("showModerated")]
public IActionResult ShowModerated() => this.Ok(LbpSerializer.BlankElement("resources"));
@ -27,6 +32,9 @@ public class ResourcesController : ControllerBase
[HttpPost("showNotUploaded")]
public async Task<IActionResult> FilterResources()
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(ResourceList));
@ -42,8 +50,11 @@ public class ResourcesController : ControllerBase
}
[HttpGet("r/{hash}")]
public IActionResult GetResource(string hash)
public async Task<IActionResult> GetResource(string hash)
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string path = FileHelper.GetResourcePath(hash);
if (FileHelper.ResourceExists(hash)) return this.File(IOFile.OpenRead(path), "application/octet-stream");
@ -51,33 +62,14 @@ public class ResourcesController : ControllerBase
return this.NotFound();
}
[ResponseCache(Duration = 86400)]
[HttpGet("/gameAssets/{hash}")]
public IActionResult GetGameImage(string hash)
{
string path = Path.Combine("png", $"{hash}.png");
if (IOFile.Exists(path))
{
return this.File(IOFile.OpenRead(path), "image/png");
}
LbpFile? file = LbpFile.FromHash(hash);
if (file != null)
{
if (ImageHelper.LbpFileToPNG(file))
{
return this.File(IOFile.OpenRead(path), "image/png");
}
}
return this.NotFound();
}
// TODO: check if this is a valid hash
[HttpPost("upload/{hash}/unattributed")]
[HttpPost("upload/{hash}")]
public async Task<IActionResult> UploadResource(string hash)
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string assetsDirectory = FileHelper.ResourcePath;
string path = FileHelper.GetResourcePath(hash);
@ -85,28 +77,46 @@ public class ResourcesController : ControllerBase
// lbp treats code 409 as success and as an indicator that the file is already present
if (FileHelper.ResourceExists(hash)) this.Conflict();
Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance);
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
Logger.Info($"Processing resource upload (hash: {hash})", LogArea.Resources);
LbpFile file = new(await readFromPipeReader(this.Request.BodyReader));
if (!FileHelper.IsFileSafe(file))
{
Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
Logger.Warn($"File is unsafe (hash: {hash}, type: {file.FileType})", LogArea.Resources);
return this.Conflict();
}
string calculatedHash = file.Hash;
if (calculatedHash != hash)
{
Logger.Log
(
$"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})",
LoggerLevelResources.Instance
);
Logger.Warn
($"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})", LogArea.Resources);
return this.Conflict();
}
Logger.Log($"File is OK! (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
Logger.Success($"File is OK! (hash: {hash}, type: {file.FileType})", LogArea.Resources);
await IOFile.WriteAllBytesAsync(path, file.Data);
return this.Ok();
}
// Written with reference from
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/request-response?view=aspnetcore-5.0
// Surprisingly doesn't take seconds. (67ms for a 100kb file)
private static async Task<byte[]> readFromPipeReader(PipeReader reader)
{
List<byte> data = new();
while (true)
{
ReadResult readResult = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = readResult.Buffer;
if (readResult.IsCompleted && buffer.Length > 0) data.AddRange(buffer.ToArray());
reader.AdvanceTo(buffer.Start, buffer.End);
if (readResult.IsCompleted) break;
}
return data.ToArray();
}
}

View file

@ -1,17 +1,15 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.Levels.Categories;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Categories;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -35,7 +33,7 @@ public class CollectionController : ControllerBase
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
string categoriesSerialized = CollectionHelper.Categories.Aggregate
string categoriesSerialized = CategoryHelper.Categories.Aggregate
(
string.Empty,
(current, category) =>
@ -64,7 +62,7 @@ public class CollectionController : ControllerBase
"hint_start", 1
},
{
"total", CollectionHelper.Categories.Count
"total", CategoryHelper.Categories.Count
},
}
)
@ -82,10 +80,10 @@ public class CollectionController : ControllerBase
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
Category? category = CollectionHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
if (category == null) return this.NotFound();
Logger.Log("Found category " + category, LoggerLevelCategory.Instance);
Logger.Debug("Found category " + category, LogArea.Category);
List<Slot> slots;
int totalSlots;

View file

@ -1,8 +1,7 @@
using System;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Levels;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/tags")]

View file

@ -1,15 +1,13 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]

View file

@ -1,20 +1,17 @@
#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Files;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Profiles;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -56,7 +53,7 @@ public class PublishController : ControllerBase
if (oldSlot == null) return this.NotFound();
if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
}
else if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerSettings.Instance.EntitledSlots)
else if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
{
return this.StatusCode(403, "");
}
@ -76,7 +73,6 @@ public class PublishController : ControllerBase
[HttpPost("publish")]
public async Task<IActionResult> Publish()
{
// User user = await this.database.UserFromGameRequest(this.Request);
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
if (userAndToken == null) return this.StatusCode(403, "");
@ -90,13 +86,13 @@ public class PublishController : ControllerBase
if (slot.Location == null) return this.BadRequest();
if (slot.Description.Length > 200) return this.BadRequest();
if (slot.Description.Length > 500) return this.BadRequest();
if (slot.Name.Length > 100) return this.BadRequest();
if (slot.Name.Length > 64) return this.BadRequest();
foreach (string resource in slot.Resources)
if (slot.Resources.Any(resource => !FileHelper.ResourceExists(resource)))
{
if (!FileHelper.ResourceExists(resource)) return this.BadRequest();
return this.BadRequest();
}
LbpFile? rootLevel = LbpFile.FromHash(slot.RootLevel);
@ -148,7 +144,14 @@ public class PublishController : ControllerBase
slot.TeamPick = oldSlot.TeamPick;
// Only update a slot's gameVersion if the level was actually change
if (oldSlot.RootLevel != slot.RootLevel) slot.GameVersion = gameToken.GameVersion;
if (oldSlot.RootLevel != slot.RootLevel)
{
slot.GameVersion = gameToken.GameVersion;
}
else
{
slot.GameVersion = oldSlot.GameVersion;
}
if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0)
{
@ -161,7 +164,7 @@ public class PublishController : ControllerBase
return this.Ok(oldSlot.Serialize(gameToken.GameVersion));
}
if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerSettings.Instance.EntitledSlots)
if (user.GetUsedSlotsForGame(gameToken.GameVersion) > ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
{
return this.StatusCode(403, "");
}
@ -192,7 +195,7 @@ public class PublishController : ControllerBase
await WebhookHelper.SendWebhook
(
"New level published!",
$"**{user.Username}** just published a new level: [**{slot.Name}**]({ServerSettings.Instance.ExternalUrl}/slot/{slot.SlotId})\n{slot.Description}"
$"**{user.Username}** just published a new level: [**{slot.Name}**]({ServerConfiguration.Instance.ExternalUrl}/slot/{slot.SlotId})\n{slot.Description}"
);
return this.Ok(slot.Serialize(gameToken.GameVersion));
@ -226,7 +229,7 @@ public class PublishController : ControllerBase
XmlSerializer serializer = new(typeof(Slot));
Slot? slot = (Slot?)serializer.Deserialize(new StringReader(bodyString));
SanitizationHelper.SanitizeStringsInClass(slot);
return slot;

View file

@ -1,20 +1,18 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Administration;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Reviews;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -98,7 +96,7 @@ public class ReviewController : ControllerBase
Review? newReview = await this.getReviewFromBody();
if (newReview == null) return this.BadRequest();
if (newReview.Text.Length > 100) return this.BadRequest();
if (newReview.Text.Length > 512) return this.BadRequest();
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == user.UserId);
@ -167,18 +165,17 @@ public class ReviewController : ControllerBase
List<Review?> reviewList = reviews.ToList();
string inner = reviewList
.Aggregate
(
string.Empty,
(current, review) =>
{
if (review == null) return current;
string inner = reviewList.Aggregate
(
string.Empty,
(current, review) =>
{
if (review == null) return current;
RatedReview? yourThumb = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId);
return current + review.Serialize(null, yourThumb);
}
);
RatedReview? yourThumb = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId);
return current + review.Serialize(null, yourThumb);
}
);
string response = LbpSerializer.TaggedStringElement
(
"reviews",

View file

@ -1,18 +1,15 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -108,7 +105,15 @@ public class ScoreController : ControllerBase
}
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
private string getScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5, string rootName = "scores")
private string getScores
(
int slotId,
int type,
User user,
int pageStart = -1,
int pageSize = 5,
string rootName = "scores"
)
{
// This is hella ugly but it technically assigns the proper rank to a score
// var needed for Anonymous type returned from SELECT

View file

@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
#nullable enable
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -24,23 +22,20 @@ public class SearchController : ControllerBase
[HttpGet("slots/search")]
public async Task<IActionResult> SearchSlots([FromQuery] string query, [FromQuery] int pageSize, [FromQuery] int pageStart)
{
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
GameToken? gameToken = await this.database.GameTokenFromRequest(this.Request);
if (gameToken == null) return this.StatusCode(403, "");
if (userAndToken == null) return this.StatusCode(403, "");
// ReSharper disable once PossibleInvalidOperationException
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
if (query == null) return this.BadRequest();
if (string.IsNullOrWhiteSpace(query)) return this.BadRequest();
query = query.ToLower();
string[] keywords = query.Split(" ");
IQueryable<Slot> dbQuery = this.database.Slots
.Include(s => s.Creator)
IQueryable<Slot> dbQuery = this.database.Slots.Include
(s => s.Creator)
.Include(s => s.Location)
.OrderBy(s => !s.TeamPick)
.ThenByDescending(s => s.FirstUploaded)
.Where(s => s.SlotId >= 0); // dumb query to conv into IQueryable
// ReSharper disable once LoopCanBeConvertedToQuery
@ -49,7 +44,7 @@ public class SearchController : ControllerBase
(
s => s.Name.ToLower().Contains(keyword) ||
s.Description.ToLower().Contains(keyword) ||
s.Creator.Username.ToLower().Contains(keyword) ||
s.Creator!.Username.ToLower().Contains(keyword) ||
s.SlotId.ToString().Equals(keyword)
);

View file

@ -1,19 +1,17 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Reviews;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -39,10 +37,10 @@ public class SlotsController : ControllerBase
string response = Enumerable.Aggregate
(
this.database.Slots.ByGameVersion(gameVersion, token.UserId == user.UserId)
this.database.Slots.ByGameVersion(gameVersion, token.UserId == user.UserId, true)
.Where(s => s.Creator!.Username == user.Username)
.Skip(pageStart - 1)
.Take(Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)),
.Take(Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)),
string.Empty,
(current, slot) => current + slot.Serialize(token.GameVersion)
);
@ -56,7 +54,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", user.UsedSlots
@ -77,7 +75,7 @@ public class SlotsController : ControllerBase
GameVersion gameVersion = token.GameVersion;
Slot? slot = await this.database.Slots.ByGameVersion(gameVersion, true).FirstOrDefaultAsync(s => s.SlotId == id);
Slot? slot = await this.database.Slots.ByGameVersion(gameVersion, true, true).FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
@ -119,8 +117,7 @@ public class SlotsController : ControllerBase
GameVersion gameVersion = token.GameVersion;
IQueryable<Slot> slots = this.database.Slots.ByGameVersion
(gameVersion)
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
.OrderByDescending(s => s.FirstUploaded)
.Skip(pageStart - 1)
.Take(Math.Min(pageSize, 30));
@ -136,7 +133,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.SlotCount()
@ -154,7 +151,7 @@ public class SlotsController : ControllerBase
GameVersion gameVersion = token.GameVersion;
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion)
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
.Where(s => s.TeamPick)
.OrderByDescending(s => s.LastUpdated)
.Skip(pageStart - 1)
@ -170,7 +167,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.TeamPickCount()
@ -188,7 +185,7 @@ public class SlotsController : ControllerBase
GameVersion gameVersion = token.GameVersion;
IEnumerable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion).OrderBy(_ => EF.Functions.Random()).Take(Math.Min(pageSize, 30));
IEnumerable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true).OrderBy(_ => EF.Functions.Random()).Take(Math.Min(pageSize, 30));
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
@ -201,7 +198,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.SlotCount()
@ -245,7 +242,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.SlotCount()
@ -303,7 +300,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.SlotCount()
@ -347,7 +344,7 @@ public class SlotsController : ControllerBase
new Dictionary<string, object>
{
{
"hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)
"hint_start", pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots)
},
{
"total", await StatisticsHelper.SlotCount()
@ -377,7 +374,7 @@ public class SlotsController : ControllerBase
{
if (version == GameVersion.LittleBigPlanetVita || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown)
{
return this.database.Slots.ByGameVersion(version);
return this.database.Slots.ByGameVersion(version, false, true);
}
string _dateFilterType = dateFilterType ?? "";

View file

@ -1,21 +1,14 @@
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/plain")]
public class StatisticsController : ControllerBase
{
private readonly Database database;
public StatisticsController(Database database)
{
this.database = database;
}
[HttpGet("playersInPodCount")]
[HttpGet("totalPlayerCount")]
public async Task<IActionResult> TotalPlayerCount() => this.Ok((await StatisticsHelper.RecentMatches()).ToString()!);

View file

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]

View file

@ -1,19 +1,16 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.GameApi;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Route("LITTLEBIGPLANETPS3_XML/")]
@ -37,12 +34,17 @@ public class UserController : ControllerBase
{
// use an anonymous type to only fetch certain columns
var partialUser = await this.database.Users.Where(u => u.Username == username)
.Select(u => new
{
u.Username,
u.IconHash,
}).FirstOrDefaultAsync();
.Select
(
u => new
{
u.Username,
u.IconHash,
}
)
.FirstOrDefaultAsync();
if (partialUser == null) return null;
string user = LbpSerializer.TaggedStringElement("npHandle", partialUser.Username, "icon", partialUser.IconHash);
return LbpSerializer.TaggedStringElement("user", user, "type", "user");
}
@ -84,13 +86,12 @@ public class UserController : ControllerBase
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
// xml hack so we can use one class to deserialize different root names
string rootElement = bodyString.Contains("updateUser") ? "updateUser" : "user";
XmlSerializer serializer = new(typeof(UserUpdate), new XmlRootAttribute(rootElement));
UserUpdate? update = (UserUpdate?) serializer.Deserialize(new StringReader(bodyString));
UserUpdate? update = (UserUpdate?)serializer.Deserialize(new StringReader(bodyString));
if (update == null) return this.BadRequest();
@ -103,11 +104,14 @@ public class UserController : ControllerBase
user.Biography = update.Biography;
}
foreach (string? resource in new[] {update.IconHash, update.YayHash, update.MehHash, update.BooHash, update.PlanetHash,})
foreach (string? resource in new[]
{
update.IconHash, update.YayHash, update.MehHash, update.BooHash, update.PlanetHash,
})
{
if (resource != null && !FileHelper.ResourceExists(resource)) return this.BadRequest();
}
if (update.IconHash != null) user.IconHash = update.IconHash;
if (update.YayHash != null) user.YayHash = update.YayHash;
@ -181,4 +185,4 @@ public class UserController : ControllerBase
return this.Ok("[{\"StatusCode\":200}]");
}
}
}

View file

@ -0,0 +1,36 @@
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
using LBPUnion.ProjectLighthouse.Servers.GameServer.Startup;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer;
public static class Program
{
public static void Main(string[] args)
{
StartupTasks.Run(args, ServerType.GameServer);
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
=> Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults
(
webBuilder =>
{
webBuilder.UseStartup<GameServerStartup>();
webBuilder.UseUrls(ServerConfiguration.Instance.GameApiListenUrl);
}
)
.ConfigureLogging
(
logging =>
{
logging.ClearProviders();
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
}
);
}

View file

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>LBPUnion.ProjectLighthouse.Servers.GameServer</AssemblyName>
<RootNamespace>LBPUnion.ProjectLighthouse.Servers.GameServer</RootNamespace>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj"/>
</ItemGroup>
<ItemGroup>
<None Remove="gitVersion.txt"/>
<EmbeddedResource Include="gitVersion.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitBranch.txt"/>
<EmbeddedResource Include="gitBranch.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitRemotes.txt"/>
<EmbeddedResource Include="gitRemotes.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<None Remove="gitUnpushed.txt"/>
<EmbeddedResource Include="gitUnpushed.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="git describe --long --always --dirty --exclude=\* --abbrev=8 &gt; &quot;$(ProjectDir)/gitVersion.txt&quot;"/>
<Exec Command="git branch --show-current &gt; &quot;$(ProjectDir)/gitBranch.txt&quot;"/>
<Exec Command="git remote -v &gt; &quot;$(ProjectDir)/gitRemotes.txt&quot;"/>
<Exec Command="git log --branches --not --remotes --oneline &gt; &quot;$(ProjectDir)/gitUnpushed.txt&quot;"/>
</Target>
</Project>

View file

@ -1,31 +1,18 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Kettu;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Middlewares;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Microsoft.OpenApi.Models;
#if RELEASE
using Microsoft.Extensions.Hosting.Internal;
#endif
namespace LBPUnion.ProjectLighthouse.Startup;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Startup;
public class Startup
public class GameServerStartup
{
public Startup(IConfiguration configuration)
public GameServerStartup(IConfiguration configuration)
{
this.Configuration = configuration;
}
@ -36,11 +23,6 @@ public class Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
#if DEBUG
services.AddRazorPages().WithRazorPagesAtContentRoot().AddRazorRuntimeCompilation();
#else
services.AddRazorPages().WithRazorPagesAtContentRoot();
#endif
services.AddMvc
(
@ -60,36 +42,6 @@ public class Startup
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
}
);
services.AddSwaggerGen
(
c =>
{
// Give swagger the name and version of our project
c.SwaggerDoc
(
"v1",
new OpenApiInfo
{
Title = "Project Lighthouse API",
Version = "v1",
}
);
// Filter out endpoints not in /api/v1
c.DocumentFilter<SwaggerFilter>();
// Add XMLDoc to swagger
string xmlDocs = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlDocs));
}
);
#if DEBUG
services.AddSingleton<IHostLifetime, DebugWarmupLifetime>();
#else
services.AddSingleton<IHostLifetime, ConsoleLifetime>();
#endif
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -97,13 +49,13 @@ public class Startup
{
bool computeDigests = true;
if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey))
if (string.IsNullOrEmpty(ServerConfiguration.Instance.DigestKey.PrimaryDigestKey))
{
Logger.Log
Logger.Warn
(
"The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " +
"To increase security, it is recommended that you find and set this variable.",
LoggerLevelStartup.Instance
LogArea.Startup
);
computeDigests = false;
}
@ -114,50 +66,7 @@ public class Startup
app.UseForwardedHeaders();
app.UseSwagger();
app.UseSwaggerUI
(
c =>
{
c.SwaggerEndpoint("v1/swagger.json", "Project Lighthouse API");
}
);
// Logs every request and the response to it
// Example: "200, 13ms: GET /LITTLEBIGPLANETPS3_XML/news"
// Example: "404, 127ms: GET /asdasd?query=osucookiezi727ppbluezenithtopplayhdhr"
app.Use
(
async (context, next) =>
{
Stopwatch requestStopwatch = new();
requestStopwatch.Start();
context.Request.EnableBuffering(); // Allows us to reset the position of Request.Body for later logging
// Log all headers.
// foreach (KeyValuePair<string, StringValues> header in context.Request.Headers) Logger.Log($"{header.Key}: {header.Value}");
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 DEBUG
// Log post body
if (context.Request.Method == "POST")
{
context.Request.Body.Position = 0;
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
}
#endif
}
);
app.UseMiddleware<RequestLogMiddleware>();
// Digest check
app.Use
@ -165,7 +74,7 @@ public class Startup
async (context, next) =>
{
// 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 == null) authCookie = string.Empty;
string digestPath = context.Request.Path;
Stream body = context.Request.Body;
@ -173,7 +82,8 @@ public class Startup
if (computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML"))
{
string clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.ServerDigestKey);
string clientRequestDigest = await CryptoHelper.ComputeDigest
(digestPath, authCookie, body, ServerConfiguration.Instance.DigestKey.PrimaryDigestKey);
// Check the digest we've just calculated against the X-Digest-A header if the game set the header. They should match.
if (context.Request.Headers.TryGetValue("X-Digest-A", out StringValues sentDigest))
@ -186,13 +96,14 @@ public class Startup
// Reset the body stream
body.Position = 0;
clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, ServerSettings.Instance.AlternateDigestKey);
clientRequestDigest = await CryptoHelper.ComputeDigest
(digestPath, authCookie, body, ServerConfiguration.Instance.DigestKey.AlternateDigestKey);
if (clientRequestDigest != sentDigest)
{
#if DEBUG
Console.WriteLine("Digest failed");
Console.WriteLine("digestKey: " + ServerSettings.Instance.ServerDigestKey);
Console.WriteLine("altDigestKey: " + ServerSettings.Instance.AlternateDigestKey);
Console.WriteLine("digestKey: " + ServerConfiguration.Instance.DigestKey.PrimaryDigestKey);
Console.WriteLine("altDigestKey: " + ServerConfiguration.Instance.DigestKey.AlternateDigestKey);
Console.WriteLine("computed digest: " + clientRequestDigest);
#endif
// We still failed to validate. Abort the request.
@ -219,10 +130,12 @@ public class Startup
{
responseBuffer.Position = 0;
string digestKey = usedAlternateDigestKey ? ServerSettings.Instance.AlternateDigestKey : ServerSettings.Instance.ServerDigestKey;
string digestKey = usedAlternateDigestKey
? ServerConfiguration.Instance.DigestKey.AlternateDigestKey
: ServerConfiguration.Instance.DigestKey.PrimaryDigestKey;
// Compute the digest for the response.
string serverDigest = await HashHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, digestKey);
string serverDigest = await CryptoHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer, digestKey);
context.Response.Headers.Add("X-Digest-A", serverDigest);
}
@ -261,8 +174,6 @@ public class Startup
app.UseRouting();
app.UseStaticFiles();
app.UseEndpoints(endpoints => endpoints.MapControllers());
app.UseEndpoints(endpoints => endpoints.MapRazorPages());
}

View file

@ -0,0 +1,15 @@
using LBPUnion.ProjectLighthouse.Middlewares;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Startup;
public class GameServerTestStartup : GameServerStartup
{
public GameServerTestStartup(IConfiguration configuration) : base(configuration)
{}
public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<FakeRemoteIPAddressMiddleware>();
base.Configure(app, env);
}
}

View file

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View file

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View file

@ -1,7 +1,7 @@
#nullable enable
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.Admin;
[ApiController]
[Route("/admin")]

View file

@ -1,13 +1,11 @@
#nullable enable
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Administration.Reports;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Reports;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.Admin;
[ApiController]
[Route("admin/report/{id:int}")]

View file

@ -1,11 +1,11 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.Admin;
[ApiController]
[Route("admin/slot/{id:int}")]

View file

@ -0,0 +1,103 @@
#nullable enable
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using IOFile = System.IO.File;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.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}");
}
/// <summary>
/// Resets the user's earth decorations to a blank state. Useful for users who abuse audio for example.
/// </summary>
[HttpGet("wipePlanets")]
public async Task<IActionResult> WipePlanets([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();
string[] hashes = {
targetedUser.PlanetHashLBP2,
targetedUser.PlanetHashLBP3,
targetedUser.PlanetHashLBPVita,
};
// This will also wipe users' earth with the same hashes.
foreach (string hash in hashes)
{
// Don't try to remove empty hashes. That's a horrible idea.
if (string.IsNullOrWhiteSpace(hash)) continue;
// Find users with a matching hash
List<User> users = await this.database.Users
.Where(u => u.PlanetHashLBP2 == hash ||
u.PlanetHashLBP3 == hash ||
u.PlanetHashLBPVita == hash)
.ToListAsync();
// We should match at least the targeted user...
System.Diagnostics.Debug.Assert(users.Count != 0);
// Reset each users' hash.
foreach (User userWithPlanet in users)
{
userWithPlanet.PlanetHashLBP2 = "";
userWithPlanet.PlanetHashLBP3 = "";
userWithPlanet.PlanetHashLBPVita = "";
Logger.Success($"Deleted planets for {userWithPlanet.Username} (id:{userWithPlanet.UserId})", LogArea.Admin);
}
// And finally, attempt to remove the resource from the filesystem. We don't want that taking up space.
try
{
IOFile.Delete(FileHelper.GetResourcePath(hash));
Logger.Success($"Deleted planet resource {hash}",
LogArea.Admin);
}
catch(DirectoryNotFoundException)
{
// This is certainly a strange case, but it's not worth doing anything about since we were about
// to delete the file anyways. Carry on~
}
catch(Exception e)
{
// Welp, guess I'll die then. We tried~
Logger.Error($"Failed to delete planet resource {hash}\n{e}", LogArea.Admin);
}
}
await this.database.SaveChangesAsync();
return this.Redirect($"/user/{targetedUser.UserId}");
}
}

View file

@ -1,12 +1,12 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Match.Rooms;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.Debug;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.Debug;
[ApiController]
[Route("debug/roomVisualizer")]
@ -25,12 +25,12 @@ public class RoomVisualizerController : ControllerBase
#if !DEBUG
return this.NotFound();
#else
List<User> users = await this.database.Users.OrderByDescending(_ => EF.Functions.Random()).Take(2).ToListAsync();
List<int> users = await this.database.Users.OrderByDescending(_ => EF.Functions.Random()).Take(2).Select(u => u.UserId).ToListAsync();
RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3);
foreach (User user in users)
foreach (int user in users)
{
MatchHelper.SetUserLocation(user.UserId, "127.0.0.1");
MatchHelper.SetUserLocation(user, "127.0.0.1");
}
return this.Redirect("/debug/roomVisualizer");
#endif
@ -42,7 +42,7 @@ public class RoomVisualizerController : ControllerBase
#if !DEBUG
return this.NotFound();
#else
RoomHelper.Rooms.RemoveAll(_ => true);
lock(RoomHelper.RoomLock) RoomHelper.Rooms.RemoveAll();
return this.Redirect("/debug/roomVisualizer");
#endif
}

View file

@ -1,13 +1,11 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.ExternalAuth;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.ExternalAuth;
[ApiController]
[Route("/authentication")]
@ -57,8 +55,6 @@ public class AuthenticationController : ControllerBase
this.database.GameTokens.Remove(authAttempt.GameToken);
this.database.AuthenticationAttempts.Remove(authAttempt);
DeniedAuthenticationHelper.SetDeniedAt($"{authAttempt.IPAddress}|{user.Username}");
await this.database.SaveChangesAsync();
return this.Redirect("~/authentication");
@ -79,8 +75,6 @@ public class AuthenticationController : ControllerBase
{
this.database.GameTokens.Remove(authAttempt.GameToken);
this.database.AuthenticationAttempts.Remove(authAttempt);
DeniedAuthenticationHelper.SetDeniedAt($"{authAttempt.IPAddress}|{user.Username}");
}
await this.database.SaveChangesAsync();

View file

@ -1,10 +1,11 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website.ExternalAuth;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers.ExternalAuth;
[ApiController]
[Route("/authentication")]

View file

@ -0,0 +1,29 @@
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Helpers;
using Microsoft.AspNetCore.Mvc;
using IOFile = System.IO.File;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers;
[ApiController]
public class ResourcesController : ControllerBase
{
[ResponseCache(Duration = 86400)]
[HttpGet("/gameAssets/{hash}")]
public IActionResult GetGameImage(string hash)
{
string path = Path.Combine("png", $"{hash}.png");
if (IOFile.Exists(path))
{
return this.File(IOFile.OpenRead(path), "image/png");
}
LbpFile? file = LbpFile.FromHash(hash);
if (file != null && FileHelper.LbpFileToPNG(file))
{
return this.File(IOFile.OpenRead(path), "image/png");
}
return this.NotFound();
}
}

View file

@ -1,10 +1,9 @@
#nullable enable
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -13,7 +12,7 @@ using Microsoft.EntityFrameworkCore;
// TODO: Clean up this file
// - jvyden
namespace LBPUnion.ProjectLighthouse.Controllers.Website;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers;
[ApiController]
[Route("slot/{id:int}")]
@ -45,14 +44,14 @@ public class SlotPageController : ControllerBase
if (msg == null)
{
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
Logger.Error($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LogArea.Comments);
return this.Redirect("~/slot/" + id);
}
msg = SanitizationHelper.SanitizeString(msg);
await this.database.PostComment(user, id, CommentType.Level, msg);
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
Logger.Success($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LogArea.Comments);
return this.Redirect("~/slot/" + id);
}

View file

@ -1,13 +1,12 @@
#nullable enable
using System.Threading.Tasks;
using Kettu;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Controllers.Website;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Controllers;
[ApiController]
[Route("user/{id:int}")]
@ -39,14 +38,14 @@ public class UserPageController : ControllerBase
if (msg == null)
{
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
Logger.Error($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LogArea.Comments);
return this.Redirect("~/user/" + id);
}
msg = SanitizationHelper.SanitizeString(msg);
await this.database.PostComment(user, id, CommentType.Profile, msg);
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
Logger.Success($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LogArea.Comments);
return this.Redirect("~/user/" + id);
}

View file

@ -1,5 +1,5 @@
@page "/admin/user/{id:int}/ban"
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminBanUserPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminBanUserPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,12 +1,11 @@
#nullable enable
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
public class AdminBanUserPage : BaseLayout
{

View file

@ -1,15 +1,27 @@
@page "/admin"
@using LBPUnion.ProjectLighthouse.Administration
@using LBPUnion.ProjectLighthouse.Administration.Maintenance
@using LBPUnion.ProjectLighthouse.Extensions
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
@using LBPUnion.ProjectLighthouse.Maintenance
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminPanelPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminPanelPage
@{
Layout = "Layouts/BaseLayout";
Model.Title = "Admin Panel";
}
@if (Model.Log != null)
{
<div class="ui bottom attached message">
<h2>Command Output</h2>
@foreach (string line in Model.Log.Split("\n"))
{
<code>@line.TrimEnd()</code><br>
}
</div>
}
@if (!this.Request.IsMobile())
{
<div class="ui center aligned grid">

View file

@ -1,13 +1,15 @@
#nullable enable
using System.Collections.Generic;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Administration;
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Maintenance;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
public class AdminPanelPage : BaseLayout
{
@ -17,7 +19,9 @@ public class AdminPanelPage : BaseLayout
public List<AdminPanelStatistic> Statistics = new();
public async Task<IActionResult> OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob)
public string? Log;
public async Task<IActionResult> OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob, [FromQuery] string? log)
{
User? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");
@ -33,8 +37,9 @@ public class AdminPanelPage : BaseLayout
args ??= "";
args = command + " " + args;
string[] split = args.Split(" ");
await MaintenanceHelper.RunCommand(split);
return this.Redirect("~/admin");
List<LogLine> runCommand = await MaintenanceHelper.RunCommand(split);
return this.Redirect($"~/admin?log={CryptoHelper.ToBase64(runCommand.ToLogString())}");
}
if (!string.IsNullOrEmpty(maintenanceJob))
@ -43,6 +48,11 @@ public class AdminPanelPage : BaseLayout
return this.Redirect("~/admin");
}
if (!string.IsNullOrEmpty(log))
{
this.Log = CryptoHelper.FromBase64(log);
}
return this.Page();
}
}

View file

@ -1,6 +1,7 @@
@page "/admin/users"
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminPanelUsersPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminPanelUsersPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,20 +1,17 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
public class AdminPanelUsersPage : BaseLayout
{
public int UserCount;
public List<User> Users;
public List<User> Users = new();
public AdminPanelUsersPage(Database database) : base(database)
{}

View file

@ -1,5 +1,5 @@
@page "/admin/user/{id:int}/setGrantedSlots"
@model LBPUnion.ProjectLighthouse.Pages.Admin.AdminSetGrantedSlotsPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin.AdminSetGrantedSlotsPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,11 +1,11 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages.Admin;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
public class AdminSetGrantedSlotsPage : BaseLayout
{

View file

@ -1,5 +1,5 @@
@page "/verifyEmail"
@model LBPUnion.ProjectLighthouse.Pages.CompleteEmailVerificationPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.CompleteEmailVerificationPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,25 +1,24 @@
#nullable enable
using System.Threading.Tasks;
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles.Email;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class CompleteEmailVerificationPage : BaseLayout
{
public CompleteEmailVerificationPage([NotNull] Database database) : base(database)
public CompleteEmailVerificationPage(Database database) : base(database)
{}
public string? Error = null;
public string? Error;
public async Task<IActionResult> OnGet(string token)
{
if (!ServerSettings.Instance.SMTPEnabled) return this.NotFound();
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
User? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");

View file

@ -1,5 +1,5 @@
@page "/debug/filter"
@model LBPUnion.ProjectLighthouse.Pages.Debug.FilterTestPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug.FilterTestPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,20 +1,19 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages.Debug;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug;
public class FilterTestPage : BaseLayout
{
public FilterTestPage(Database database) : base(database)
{}
public string? FilteredText = null;
public string? Text = null;
public string? FilteredText;
public string? Text;
public async Task<IActionResult> OnGet(string? text = null)
public IActionResult OnGet(string? text = null)
{
#if !DEBUG
return this.NotFound();

View file

@ -1,8 +1,11 @@
@page "/debug/roomVisualizer"
@using LBPUnion.ProjectLighthouse.Extensions
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Match.Rooms
@using LBPUnion.ProjectLighthouse.PlayerData
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
@using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Match
@model LBPUnion.ProjectLighthouse.Pages.Debug.RoomVisualizerPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug.RoomVisualizerPage
@{
Layout = "Layouts/BaseLayout";
@ -35,7 +38,7 @@
<meta http-equiv="refresh" content="@refreshSeconds">
</noscript>
<p>@RoomHelper.Rooms.Count rooms</p>
<p>@RoomHelper.Rooms.Count() rooms</p>
<a href="/debug/roomVisualizer/createFakeRoom">
<div class="ui blue button">Create Fake Room</div>
@ -50,6 +53,7 @@
<h2>Best rooms for each game version</h2>
@foreach (GameVersion version in Enum.GetValues<GameVersion>())
{
#nullable enable
if (version == GameVersion.LittleBigPlanet1 || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown) continue;
FindBestRoomResponse? response = RoomHelper.FindBestRoom(null, version, null, null, null);
@ -62,7 +66,7 @@
@foreach (Room room in RoomHelper.Rooms)
{
bool userInRoom = room.Players.Select(p => p.Username).Contains(Model.User?.Username);
bool userInRoom = room.PlayerIds.Contains(Model.User?.UserId ?? -1);
string color = userInRoom ? "green" : "blue";
<div class="ui @color inverted segment">
<h3>Room @room.RoomId</h3>
@ -72,9 +76,9 @@
<b>You are currently in this room.</b>
</p>
}
<p>@room.Players.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString()on paltform @room.RoomPlatform</p>
<p>@room.PlayerIds.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString() on platform @room.RoomPlatform</p>
<p>Slot type: @room.Slot.SlotType, slot id: @room.Slot.SlotId</p>
@foreach (User player in room.Players)
@foreach (User player in room.GetPlayers(Model.Database))
{
<div class="ui segment">@player.Username</div>
}

View file

@ -1,26 +1,26 @@
#nullable enable
using System.Threading.Tasks;
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages.Debug;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using Microsoft.AspNetCore.Mvc;
#if !DEBUG
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
#endif
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug;
public class RoomVisualizerPage : BaseLayout
{
public RoomVisualizerPage([NotNull] Database database) : base(database)
public RoomVisualizerPage(Database database) : base(database)
{}
public async Task<IActionResult> OnGet()
public IActionResult OnGet()
{
#if !DEBUG
User? user = this.Database.UserFromWebRequest(this.Request);
if (user == null || !user.IsAdmin) return this.NotFound();
#endif
return this.Page();
#else
return this.Page();
#endif
}
}

View file

@ -1,6 +1,6 @@
@page "/debug/version"
@using LBPUnion.ProjectLighthouse.Helpers
@model LBPUnion.ProjectLighthouse.Pages.Debug.VersionInfoPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug.VersionInfoPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,8 +1,8 @@
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages.Debug;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Debug;
public class VersionInfoPage : BaseLayout
{

View file

@ -1,6 +1,7 @@
@page "/authentication"
@using LBPUnion.ProjectLighthouse.PlayerData
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Pages.ExternalAuth.AuthenticationPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth.AuthenticationPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,28 +1,26 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages.ExternalAuth;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth;
public class AuthenticationPage : BaseLayout
{
public List<AuthenticationAttempt> AuthenticationAttempts;
public List<AuthenticationAttempt> AuthenticationAttempts = new();
public IPAddress? IpAddress;
public AuthenticationPage(Database database) : base(database)
{}
public async Task<IActionResult> OnGet()
public IActionResult OnGet()
{
if (!ServerSettings.Instance.UseExternalAuth) return this.NotFound();
if (!ServerConfiguration.Instance.Authentication.UseExternalAuth) return this.NotFound();
if (this.User == null) return this.StatusCode(403, "");
this.IpAddress = this.HttpContext.Connection.RemoteIpAddress;

View file

@ -1,6 +1,7 @@
@page "/authentication/autoApprovals"
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Pages.ExternalAuth.ManageUserApprovedIpAddressesPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth.ManageUserApprovedIpAddressesPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,18 +1,16 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages.ExternalAuth;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth;
public class ManageUserApprovedIpAddressesPage : BaseLayout
{
public List<UserApprovedIpAddress> ApprovedIpAddresses = new();
public List<UserApprovedIpAddress> ApprovedIpAddresses;
public ManageUserApprovedIpAddressesPage(Database database) : base(database)
{}

View file

@ -1,21 +1,21 @@
@page "/"
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
@using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Levels
@using LBPUnion.ProjectLighthouse.Types.Settings
@model LBPUnion.ProjectLighthouse.Pages.LandingPage
@using LBPUnion.ProjectLighthouse.Configuration
@using LBPUnion.ProjectLighthouse.Extensions
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
@using LBPUnion.ProjectLighthouse.Levels
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LandingPage
@{
Layout = "Layouts/BaseLayout";
Model.ShowTitleInPage = false;
bool isMobile = this.Request.IsMobile();
}
<h1>Welcome to <b>Project Lighthouse</b>!</h1>
<h1>Welcome to <b>@ServerConfiguration.Instance.Customization.ServerName</b>!</h1>
@if (Model.User != null)
{
<p>You are currently logged in as <b>@Model.User.Username</b>.</p>
if (ServerSettings.Instance.UseExternalAuth && Model.AuthenticationAttemptsCount > 0)
if (ServerConfiguration.Instance.Authentication.UseExternalAuth && Model.AuthenticationAttemptsCount > 0)
{
<p>
<b>You have @Model.AuthenticationAttemptsCount authentication attempts pending. Click <a href="/authentication">here</a> to view them.</b>
@ -53,7 +53,7 @@ else
<h1><i class="ribbon icon"></i>Latest Team Picks</h1>
<div class="ui divider"></div>
<div class="ui left aligned segment">
@foreach (Slot slot in Model.LatestTeamPicks)
@foreach (Slot slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
{
@await Html.PartialAsync("Partials/SlotCardPartial", slot, Model.GetSlotViewData(slot.SlotId, isMobile))
<br>
@ -70,7 +70,7 @@ else
<h1><i class="certificate icon"></i>Newest Levels</h1>
<div class="ui divider"></div>
<div class="ui left aligned segment">
@foreach (Slot slot in Model.NewestLevels)
@foreach (Slot slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
{
@await Html.PartialAsync("Partials/SlotCardPartial", slot, Model.GetSlotViewData(slot.SlotId, isMobile))
<br>

View file

@ -1,17 +1,14 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class LandingPage : BaseLayout
{
@ -19,12 +16,12 @@ public class LandingPage : BaseLayout
{}
public int AuthenticationAttemptsCount;
public List<User> PlayersOnline;
public List<User> PlayersOnline = new();
public int PlayersOnlineCount;
public List<Slot> LatestTeamPicks;
public List<Slot> NewestLevels;
public List<Slot>? LatestTeamPicks;
public List<Slot>? NewestLevels;
[UsedImplicitly]
public async Task<IActionResult> OnGet()
@ -39,7 +36,7 @@ public class LandingPage : BaseLayout
(a => a.GameToken)
.CountAsync(a => a.GameToken.UserId == user.UserId);
List<int> userIds = await this.Database.LastContacts.Where(l => TimestampHelper.Timestamp - l.Timestamp < 300).Select(l => l.UserId).ToListAsync();
List<int> userIds = await this.Database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300).Select(l => l.UserId).ToListAsync();
this.PlayersOnline = await this.Database.Users.Where(u => userIds.Contains(u.UserId)).ToListAsync();

View file

@ -1,8 +1,8 @@
@using LBPUnion.ProjectLighthouse.Configuration
@using LBPUnion.ProjectLighthouse.Extensions
@using LBPUnion.ProjectLighthouse.Helpers
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
@using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Settings
@model LBPUnion.ProjectLighthouse.Pages.Layouts.BaseLayout
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts.BaseLayout
@{
if (Model!.User == null)
@ -11,7 +11,7 @@
}
else
{
if (ServerSettings.Instance.UseExternalAuth)
if (ServerConfiguration.Instance.Authentication.UseExternalAuth)
{
Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key"));
}
@ -25,7 +25,6 @@
}
Model.IsMobile = Model.Request.IsMobile();
long timeStarted = TimestampHelper.TimestampMillis;
}
<!DOCTYPE html>
@ -34,11 +33,11 @@
<head>
@if (Model.Title == string.Empty)
{
<title>Project Lighthouse</title>
<title>@ServerConfiguration.Instance.Customization.ServerName</title>
}
else
{
<title>Project Lighthouse - @Model.Title</title>
<title>@ServerConfiguration.Instance.Customization.ServerName - @Model.Title</title>
}
<link rel="stylesheet" type="text/css" href="~/css/styles.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.8/dist/semantic.min.css">
@ -53,7 +52,7 @@
@* Embed Stuff *@
<meta name="theme-color" data-react-helmet="true" content="#008cff">
<meta content="Project Lighthouse - @Model.Title" property="og:title">
<meta content="@ServerConfiguration.Instance.Customization.ServerName - @Model.Title" property="og:title">
@if (!string.IsNullOrEmpty(Model.Description))
{
<meta content="@Model.Description" property="og:description">
@ -62,16 +61,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@* Google Analytics *@
@if (ServerSettings.Instance.GoogleAnalyticsEnabled)
@if (ServerConfiguration.Instance.GoogleAnalytics.AnalyticsEnabled)
{
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=@ServerSettings.Instance.GoogleAnalyticsId"></script>
<script async src="https://www.googletagmanager.com/gtag/js?id=@ServerConfiguration.Instance.GoogleAnalytics.Id"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '@ServerSettings.Instance.GoogleAnalyticsId');
gtag('config', '@ServerConfiguration.Instance.GoogleAnalytics.Id');
</script>
}
</head>
@ -179,7 +178,6 @@
<p>Model.Title: @Model.Title</p>
<p>Model.Description: @Model.Description</p>
<p>Model.User.UserId: @(Model.User?.UserId.ToString() ?? "(not logged in)")</p>
<p>Render time: ~@(TimestampHelper.TimestampMillis - timeStarted)ms</p>
</div>
</div>
</div>

View file

@ -1,9 +1,9 @@
#nullable enable
using System.Collections.Generic;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace LBPUnion.ProjectLighthouse.Pages.Layouts;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
public class BaseLayout : PageModel
{

View file

@ -1,6 +1,6 @@
@page "/login"
@using LBPUnion.ProjectLighthouse.Types.Settings
@model LBPUnion.ProjectLighthouse.Pages.LoginForm
@using LBPUnion.ProjectLighthouse.Configuration
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LoginForm
@{
Layout = "Layouts/BaseLayout";
@ -50,13 +50,13 @@
</div>
</div>
@if (ServerSettings.Instance.HCaptchaEnabled)
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
{
@await Html.PartialAsync("Partials/CaptchaPartial")
}
<input type="submit" value="Log in" id="submit" class="ui blue button">
@if (ServerSettings.Instance.RegistrationEnabled)
@if (ServerConfiguration.Instance.Authentication.RegistrationEnabled)
{
<a href="/register">
<div class="ui button">

View file

@ -1,27 +1,25 @@
#nullable enable
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kettu;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles.Email;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class LoginForm : BaseLayout
{
public LoginForm(Database database) : base(database)
{}
public string Error { get; private set; }
public string? Error { get; private set; }
[UsedImplicitly]
public async Task<IActionResult> OnPost(string username, string password)
@ -38,7 +36,7 @@ public class LoginForm : BaseLayout
return this.Page();
}
if (!await Request.CheckCaptchaValidity())
if (!await this.Request.CheckCaptchaValidity())
{
this.Error = "You must complete the captcha correctly.";
return this.Page();
@ -47,34 +45,34 @@ public class LoginForm : BaseLayout
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (user == null)
{
Logger.Log($"User {username} failed to login on web due to invalid username", LoggerLevelLogin.Instance);
Logger.Warn($"User {username} failed to login on web due to invalid username", LogArea.Login);
this.Error = "The username or password you entered is invalid.";
return this.Page();
}
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);
Logger.Warn($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", LogArea.Login);
this.Error = "The username or password you entered is invalid.";
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);
Logger.Warn($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", LogArea.Login);
this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason;
return this.Page();
}
if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled)
if (user.EmailAddress == null && ServerConfiguration.Instance.Mail.MailEnabled)
{
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login; email not set", LoggerLevelLogin.Instance);
Logger.Warn($"User {user.Username} (id: {user.UserId}) failed to login; email not set", LogArea.Login);
EmailSetToken emailSetToken = new()
{
UserId = user.UserId,
User = user,
EmailToken = HashHelper.GenerateAuthToken(),
EmailToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.EmailSetTokens.Add(emailSetToken);
@ -86,7 +84,7 @@ public class LoginForm : BaseLayout
WebToken webToken = new()
{
UserId = user.UserId,
UserToken = HashHelper.GenerateAuthToken(),
UserToken = CryptoHelper.GenerateAuthToken(),
};
this.Database.WebTokens.Add(webToken);
@ -102,18 +100,14 @@ public class LoginForm : BaseLayout
}
);
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance);
Logger.Success($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LogArea.Login);
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
if (ServerConfiguration.Instance.Mail.MailEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
return this.RedirectToPage(nameof(LandingPage));
}
[UsedImplicitly]
public async Task<IActionResult> OnGet()
{
this.Error = string.Empty;
return this.Page();
}
public IActionResult OnGet() => this.Page();
}

View file

@ -1,5 +1,5 @@
@page "/logout"
@model LBPUnion.ProjectLighthouse.Pages.LogoutPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.LogoutPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,10 +1,10 @@
#nullable enable
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class LogoutPage : BaseLayout
{

View file

@ -1,4 +1,4 @@
@model LBPUnion.ProjectLighthouse.Types.AdminPanelStatistic
@model LBPUnion.ProjectLighthouse.Administration.AdminPanelStatistic
<div class="three wide column">
<div class="ui center aligned blue segment">

View file

@ -1,4 +1,4 @@
@model LBPUnion.ProjectLighthouse.Types.User
@model LBPUnion.ProjectLighthouse.PlayerData.Profiles.User
<form method="post" action="/admin/user/@Model.UserId/setGrantedSlots">
@Html.AntiForgeryToken()

View file

@ -0,0 +1,6 @@
@using LBPUnion.ProjectLighthouse.Configuration
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled)
{
<div class="h-captcha" data-sitekey="@ServerConfiguration.Instance.Captcha.SiteKey"></div>
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
}

View file

@ -1,6 +1,5 @@
@using System.IO
@using System.Web
@using LBPUnion.ProjectLighthouse.Types.Profiles
@using System.Web
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
<div class="ui yellow segment" id="comments">
<h2>Comments</h2>
@if (Model.Comments.Count == 0 && Model.CommentsEnabled)
@ -28,7 +27,10 @@
</div>
<input type="submit" class="ui blue button">
</form>
<br>
@if (Model.Comments.Count > 0)
{
<div class="ui divider"></div>
}
}
@for(int i = 0; i < Model.Comments.Count; i++)
@ -39,7 +41,8 @@
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
string decodedMessage = messageWriter.ToString();
string url = Url.RouteUrl(ViewContext.RouteData.Values);
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
if (url == null) continue;
int rating = comment.ThumbsUp - comment.ThumbsDown;

View file

@ -1,5 +1,6 @@
@using LBPUnion.ProjectLighthouse.PlayerData
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Types.Photo
@model LBPUnion.ProjectLighthouse.PlayerData.Photo
<div style="position: relative">

View file

@ -1,17 +1,18 @@
@using LBPUnion.ProjectLighthouse
@using LBPUnion.ProjectLighthouse.Types
@using LBPUnion.ProjectLighthouse.Types.Settings
@using LBPUnion.ProjectLighthouse.Configuration
@using LBPUnion.ProjectLighthouse.PlayerData
@using LBPUnion.ProjectLighthouse.PlayerData.Profiles
@using Microsoft.EntityFrameworkCore
@model LBPUnion.ProjectLighthouse.Types.Levels.Slot
@model LBPUnion.ProjectLighthouse.Levels.Slot
@{
User user = (User)ViewData["User"];
User? user = (User?)ViewData["User"];
await using Database database = new();
string slotName = string.IsNullOrEmpty(Model.Name) ? "Unnamed Level" : Model.Name;
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
bool mini = (bool?)ViewData["IsMini"] ?? false;
bool isQueued = false;
@ -20,15 +21,14 @@
if (user != null)
{
isQueued = await database.QueuedLevels.FirstOrDefaultAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId) != null;
isHearted = await database.HeartedLevels.FirstOrDefaultAsync(h => h.SlotId == Model.SlotId && h.UserId == user.UserId) != null;
}
string callbackUrl = (string)ViewData["CallbackUrl"];
string callbackUrl = (string)ViewData["CallbackUrl"]!;
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
string iconHash = Model.IconHash;
if (string.IsNullOrWhiteSpace(iconHash) || iconHash.StartsWith('g')) iconHash = ServerSettings.Instance.MissingIconHash;
if (string.IsNullOrWhiteSpace(iconHash) || iconHash.StartsWith('g')) iconHash = ServerConfiguration.Instance.WebsiteConfiguration.MissingIconHash;
}
<div class="card">
@{
@ -72,7 +72,7 @@
<div class="cardStatsUnderTitle">
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
<i class="blue play icon" title="Plays"></i> <span>@Model.Plays</span>
<i class="blue play icon" title="Plays"></i> <span>@Model.PlaysUnique</span>
<i class="green thumbs up icon" title="Yays"></i> <span>@Model.Thumbsup</span>
<i class="red thumbs down icon" title="Boos"></i> <span>@Model.Thumbsdown</span>
@ -82,7 +82,6 @@
<span>@Model.RatingLBP1</span>
}
</div>
<p>
<i>Created by <a href="/user/@Model.Creator?.UserId">@Model.Creator?.Username</a> for @Model.GameVersion.ToPrettyString()</i>
</p>

View file

@ -1,4 +1,4 @@
@model LBPUnion.ProjectLighthouse.Types.User
@model LBPUnion.ProjectLighthouse.PlayerData.Profiles.User
@{
bool showLink = (bool?)ViewData["ShowLink"] ?? false;

View file

@ -1,5 +1,5 @@
@page "/passwordReset"
@model LBPUnion.ProjectLighthouse.Pages.PasswordResetPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.PasswordResetPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,19 +1,20 @@
#nullable enable
using System.Threading.Tasks;
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class PasswordResetPage : BaseLayout
{
public PasswordResetPage(Database database) : base(database)
{}
public string Error { get; private set; }
public string? Error { get; private set; }
[UsedImplicitly]
public async Task<IActionResult> OnPost(string password, string confirmPassword)
@ -33,12 +34,13 @@ public class PasswordResetPage : BaseLayout
return this.Page();
}
user.Password = HashHelper.BCryptHash(password);
user.Password = CryptoHelper.BCryptHash(password);
user.PasswordResetRequired = false;
await this.Database.SaveChangesAsync();
if (!user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
if (!user.EmailAddressVerified && ServerConfiguration.Instance.Mail.MailEnabled)
return this.Redirect("~/login/sendVerificationEmail");
return this.Redirect("~/");
}

View file

@ -1,5 +1,5 @@
@page "/passwordResetRequired"
@model LBPUnion.ProjectLighthouse.Pages.PasswordResetRequiredPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.PasswordResetRequiredPage
@{
Layout = "Layouts/BaseLayout";

View file

@ -1,20 +1,19 @@
#nullable enable
using System.Threading.Tasks;
using JetBrains.Annotations;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
namespace LBPUnion.ProjectLighthouse.Pages;
namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages;
public class PasswordResetRequiredPage : BaseLayout
{
public PasswordResetRequiredPage([NotNull] Database database) : base(database)
public PasswordResetRequiredPage(Database database) : base(database)
{}
public bool WasResetRequest { get; private set; }
public async Task<IActionResult> OnGet()
public IActionResult OnGet()
{
User? user = this.Database.UserFromWebRequest(this.Request);
if (user == null) return this.Redirect("~/login");

View file

@ -1,6 +1,7 @@
@page "/photos/{pageNumber:int}"
@using LBPUnion.ProjectLighthouse.PlayerData
@using LBPUnion.ProjectLighthouse.Types
@model LBPUnion.ProjectLighthouse.Pages.PhotosPage
@model LBPUnion.ProjectLighthouse.Servers.Website.Pages.PhotosPage
@{
Layout = "Layouts/BaseLayout";
@ -26,10 +27,10 @@
@if (Model.PageNumber != 0)
{
<a href="/photos/@(Model.PageNumber - 1)@(Model.SearchValue.Length == 0 ? "" : "?name=" + Model.SearchValue)">Previous Page</a>
<a href="/photos/@(Model.PageNumber - 1)@(Model.SearchValue?.Length == 0 ? "" : "?name=" + Model.SearchValue)">Previous Page</a>
}
@(Model.PageNumber + 1) / @(Model.PageAmount)
@if (Model.PageNumber < Model.PageAmount - 1)
{
<a href="/photos/@(Model.PageNumber + 1)@(Model.SearchValue.Length == 0 ? "" : "?name=" + Model.SearchValue)">Next Page</a>
<a href="/photos/@(Model.PageNumber + 1)@(Model.SearchValue?.Length == 0 ? "" : "?name=" + Model.SearchValue)">Next Page</a>
}

Some files were not shown because too many files have changed in this diff Show more