mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-09-25 10:49:01 +00:00
Server digest support for LBP 1 and LBP 3
This commit is contained in:
parent
db0a57b44c
commit
90201150cc
13 changed files with 368 additions and 146 deletions
1
.idea/.idea.ProjectLighthouse/.idea/.name
generated
Normal file
1
.idea/.idea.ProjectLighthouse/.idea/.name
generated
Normal file
|
@ -0,0 +1 @@
|
|||
ProjectLighthouse
|
|
@ -2,36 +2,44 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/plain")]
|
||||
public class ClientConfigurationController : ControllerBase {
|
||||
public class ClientConfigurationController : ControllerBase
|
||||
{
|
||||
[HttpGet("network_settings.nws")]
|
||||
[SuppressMessage("ReSharper", "StringLiteralTypo")]
|
||||
public IActionResult NetworkSettings() {
|
||||
return this.Ok("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 true\nAllowModeratedPoppetItems true\nShowLevelBoos true\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 120.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 30.0\nTIMEOUT_DIVE_IN_TOTAL 1000000.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\nCDNHostName localhost\nTelemetryServer localhost\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");
|
||||
public IActionResult NetworkSettings()
|
||||
{
|
||||
return this.Ok(
|
||||
"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 true\nAllowModeratedPoppetItems true\nShowLevelBoos true\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 120.0\nTIMEOUT_WAIT_FOR_FIND_BEST_ROOM 30.0\nTIMEOUT_DIVE_IN_TOTAL 1000000.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\nCDNHostName localhost\nTelemetryServer localhost\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");
|
||||
}
|
||||
|
||||
[HttpGet("t_conf")]
|
||||
[Produces("text/json")]
|
||||
public IActionResult Conf() {
|
||||
public IActionResult Conf()
|
||||
{
|
||||
return this.Ok("[{\"StatusCode\":200}]");
|
||||
}
|
||||
|
||||
[HttpGet("farc_hashes")]
|
||||
public IActionResult FarcHashes() {
|
||||
public IActionResult FarcHashes()
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
[HttpGet("privacySettings")]
|
||||
[Produces("text/xml")]
|
||||
public IActionResult PrivacySettings() {
|
||||
PrivacySettings ps = new() {
|
||||
public IActionResult PrivacySettings()
|
||||
{
|
||||
PrivacySettings ps = new()
|
||||
{
|
||||
LevelVisibility = "all",
|
||||
ProfileVisibility = "all",
|
||||
};
|
||||
|
||||
|
||||
return this.Ok(ps.Serialize());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,34 +5,41 @@ using LBPUnion.ProjectLighthouse.Types;
|
|||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/login")]
|
||||
[Produces("text/xml")]
|
||||
public class LoginController : ControllerBase {
|
||||
public class LoginController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
|
||||
public LoginController(Database database) {
|
||||
public LoginController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Login() {
|
||||
public async Task<IActionResult> Login()
|
||||
{
|
||||
string body = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
LoginData loginData;
|
||||
try {
|
||||
try
|
||||
{
|
||||
loginData = LoginData.CreateFromString(body);
|
||||
}
|
||||
catch {
|
||||
catch
|
||||
{
|
||||
return this.BadRequest();
|
||||
}
|
||||
|
||||
Token? token = await this.database.AuthenticateUser(loginData);
|
||||
|
||||
if(token == null) return this.StatusCode(403, "");
|
||||
if (token == null) return this.StatusCode(403, "");
|
||||
|
||||
return this.Ok(new LoginResult {
|
||||
return this.Ok(new LoginResult
|
||||
{
|
||||
AuthTicket = "MM_AUTH=" + token.UserToken,
|
||||
LbpEnvVer = ServerSettings.ServerName,
|
||||
}.Serialize());
|
||||
|
|
|
@ -11,57 +11,70 @@ using LBPUnion.ProjectLighthouse.Types.Profiles;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class MatchController : ControllerBase {
|
||||
public class MatchController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public MatchController(Database database) {
|
||||
|
||||
public MatchController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpPost("match")]
|
||||
[Produces("text/json")]
|
||||
public async Task<IActionResult> Match() {
|
||||
public async Task<IActionResult> Match()
|
||||
{
|
||||
|
||||
User? user = await this.database.UserFromRequest(this.Request);
|
||||
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
#region Parse match data
|
||||
|
||||
// Example POST /match: [UpdateMyPlayerData,["Player":"FireGamer9872"]]
|
||||
|
||||
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
if(bodyString.Contains("FindBestRoom")) {
|
||||
return this.Ok("[{\"StatusCode\":200},{\"Players\":[{\"PlayerId\":\"literally1984\",\"matching_res\":0},{\"PlayerId\":\"jvyden\",\"matching_res\":1}],\"Slots\":[[5,0]],\"RoomState\":\"E_ROOM_IN_POD\",\"HostMood\":\"E_MOOD_EVERYONE\",\"LevelCompletionEstimate\":0,\"PassedNoJoinPoint\":0,\"MoveConnected\":false,\"Location\":[\"127.0.0.1\"],\"BuildVersion\":289,\"Language\":1,\"FirstSeenTimestamp\":1427331263756,\"LastSeenTimestamp\":1635112546000,\"GameId\":1,\"NatType\":2,\"Friends\":[],\"Blocked\":[],\"RecentlyLeft\":[],\"FailedJoin\":[]}]");
|
||||
if (bodyString.Contains("FindBestRoom"))
|
||||
{
|
||||
return this.Ok(
|
||||
"[{\"StatusCode\":200},{\"Players\":[{\"PlayerId\":\"literally1984\",\"matching_res\":0},{\"PlayerId\":\"jvyden\",\"matching_res\":1}],\"Slots\":[[5,0]],\"RoomState\":\"E_ROOM_IN_POD\",\"HostMood\":\"E_MOOD_EVERYONE\",\"LevelCompletionEstimate\":0,\"PassedNoJoinPoint\":0,\"MoveConnected\":false,\"Location\":[\"127.0.0.1\"],\"BuildVersion\":289,\"Language\":1,\"FirstSeenTimestamp\":1427331263756,\"LastSeenTimestamp\":1635112546000,\"GameId\":1,\"NatType\":2,\"Friends\":[],\"Blocked\":[],\"RecentlyLeft\":[],\"FailedJoin\":[]}]");
|
||||
}
|
||||
|
||||
if(bodyString[0] != '[') return this.BadRequest();
|
||||
|
||||
if (bodyString[0] != '[') return this.BadRequest();
|
||||
|
||||
IMatchData? matchData;
|
||||
try {
|
||||
try
|
||||
{
|
||||
matchData = MatchHelper.Deserialize(bodyString);
|
||||
}
|
||||
catch(Exception e) {
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Log("Exception while parsing MatchData: " + e);
|
||||
Logger.Log("Data: " + bodyString);
|
||||
|
||||
return this.BadRequest();
|
||||
}
|
||||
|
||||
if(matchData == null) return this.BadRequest();
|
||||
|
||||
if (matchData == null) return this.BadRequest();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update LastMatch
|
||||
|
||||
LastMatch? lastMatch = await this.database.LastMatches
|
||||
.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync();
|
||||
|
||||
// below makes it not look like trash
|
||||
// ReSharper disable once ConvertIfStatementToNullCoalescingExpression
|
||||
if(lastMatch == null) {
|
||||
lastMatch = new LastMatch {
|
||||
if (lastMatch == null)
|
||||
{
|
||||
lastMatch = new LastMatch
|
||||
{
|
||||
UserId = user.UserId,
|
||||
};
|
||||
this.database.LastMatches.Add(lastMatch);
|
||||
|
@ -70,14 +83,16 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
lastMatch.Timestamp = TimestampHelper.Timestamp;
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
return this.Ok("[{\"StatusCode\":200}]");
|
||||
}
|
||||
|
||||
[HttpGet("playersInPodCount")]
|
||||
[HttpGet("totalPlayerCount")]
|
||||
public async Task<IActionResult> TotalPlayerCount() {
|
||||
public async Task<IActionResult> TotalPlayerCount()
|
||||
{
|
||||
int recentMatches = await this.database.LastMatches
|
||||
.Where(l => TimestampHelper.Timestamp - l.Timestamp < 60)
|
||||
.CountAsync();
|
||||
|
|
|
@ -3,38 +3,48 @@ using System.Threading.Tasks;
|
|||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/plain")]
|
||||
public class MessageController : ControllerBase {
|
||||
public class MessageController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public MessageController(Database database) {
|
||||
|
||||
public MessageController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("eula")]
|
||||
public async Task<IActionResult> Eula() {
|
||||
public async Task<IActionResult> Eula()
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
return user == null ? this.StatusCode(403, "") :
|
||||
this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n" +
|
||||
"This is a private testing instance. Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.");
|
||||
return user == null
|
||||
? this.Ok("You aren't logged in, but you're connected to a private LBP server.")
|
||||
: this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n" +
|
||||
"This is a private testing instance. Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.");
|
||||
}
|
||||
|
||||
[HttpGet("announce")]
|
||||
public IActionResult Announce() {
|
||||
public IActionResult Announce()
|
||||
{
|
||||
return this.Ok("");
|
||||
}
|
||||
|
||||
[HttpGet("notification")]
|
||||
public IActionResult Notification() {
|
||||
public IActionResult Notification()
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Filters chat messages sent by a user.
|
||||
/// </summary>
|
||||
[HttpPost("filter")]
|
||||
public async Task<IActionResult> Filter() {
|
||||
public async Task<IActionResult> Filter()
|
||||
{
|
||||
return this.Ok(await new StreamReader(this.Request.Body).ReadToEndAsync());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,30 @@
|
|||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.News;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/news")]
|
||||
[Produces("text/xml")]
|
||||
public class NewsController : ControllerBase {
|
||||
public class NewsController : ControllerBase
|
||||
{
|
||||
[HttpGet("/developer_videos")]
|
||||
public async Task<IActionResult> DeveloperVideos()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Get() {
|
||||
string newsEntry = LbpSerializer.StringElement("item", new NewsEntry {
|
||||
public IActionResult Get()
|
||||
{
|
||||
string newsEntry = LbpSerializer.StringElement("item", new NewsEntry
|
||||
{
|
||||
Category = "no_category",
|
||||
Summary = "test summary",
|
||||
Image = new NewsImage {
|
||||
Image = new NewsImage
|
||||
{
|
||||
Hash = "4947269c5f7061b27225611ee58a9a91a8031bbe",
|
||||
Alignment = "right",
|
||||
},
|
||||
|
@ -21,7 +33,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
Text = "Test Text",
|
||||
Date = 1348755214000,
|
||||
}.Serialize());
|
||||
|
||||
|
||||
return this.Ok(LbpSerializer.StringElement("news", newsEntry));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,60 +10,68 @@ using LBPUnion.ProjectLighthouse.Types.Files;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using IOFile = System.IO.File;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class ResourcesController : ControllerBase {
|
||||
public class ResourcesController : ControllerBase
|
||||
{
|
||||
[HttpPost("showModerated")]
|
||||
public IActionResult ShowModerated() {
|
||||
public IActionResult ShowModerated()
|
||||
{
|
||||
return this.Ok(LbpSerializer.BlankElement("resources"));
|
||||
}
|
||||
|
||||
[HttpPost("filterResources")]
|
||||
[HttpPost("showNotUploaded")]
|
||||
public async Task<IActionResult> FilterResources() {
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
XmlSerializer serializer = new(typeof(ResourceList));
|
||||
ResourceList resourceList = (ResourceList)serializer.Deserialize(new StringReader(bodyString));
|
||||
public async Task<IActionResult> FilterResources()
|
||||
{
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
if(resourceList == null) return this.BadRequest();
|
||||
XmlSerializer serializer = new(typeof(ResourceList));
|
||||
ResourceList resourceList = (ResourceList) serializer.Deserialize(new StringReader(bodyString));
|
||||
|
||||
if (resourceList == null) return this.BadRequest();
|
||||
|
||||
string resources = resourceList.Resources
|
||||
.Where(s => !FileHelper.ResourceExists(s))
|
||||
.Aggregate("", (current, hash) =>
|
||||
.Aggregate("", (current, hash) =>
|
||||
current + LbpSerializer.StringElement("resource", hash));
|
||||
|
||||
return this.Ok(LbpSerializer.StringElement("resources", resources));
|
||||
}
|
||||
|
||||
[HttpGet("r/{hash}")]
|
||||
public IActionResult GetResource(string hash) {
|
||||
public IActionResult GetResource(string hash)
|
||||
{
|
||||
string path = FileHelper.GetResourcePath(hash);
|
||||
|
||||
if(FileHelper.ResourceExists(hash)) {
|
||||
if (FileHelper.ResourceExists(hash))
|
||||
{
|
||||
return this.File(IOFile.OpenRead(path), "application/octet-stream");
|
||||
}
|
||||
|
||||
return this.NotFound();
|
||||
}
|
||||
|
||||
// TODO: check if this is a valid hash
|
||||
[HttpPost("upload/{hash}")]
|
||||
[AllowSynchronousIo]
|
||||
public async Task<IActionResult> UploadResource(string hash) {
|
||||
public async Task<IActionResult> UploadResource(string hash)
|
||||
{
|
||||
|
||||
string assetsDirectory = FileHelper.ResourcePath;
|
||||
string path = FileHelper.GetResourcePath(hash);
|
||||
|
||||
|
||||
FileHelper.EnsureDirectoryCreated(assetsDirectory);
|
||||
if(FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded
|
||||
if (FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded
|
||||
|
||||
Logger.Log($"Processing resource upload (hash: {hash})");
|
||||
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(Request.BodyReader));
|
||||
|
||||
if(!FileHelper.IsFileSafe(file)) return this.UnprocessableEntity();
|
||||
|
||||
if (!FileHelper.IsFileSafe(file)) return this.UnprocessableEntity();
|
||||
|
||||
await IOFile.WriteAllBytesAsync(path, file.Data);
|
||||
return this.Ok();
|
||||
}
|
||||
|
|
|
@ -8,26 +8,37 @@ using LBPUnion.ProjectLighthouse.Types.Profiles;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers {
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/xml")]
|
||||
public class UserController : ControllerBase {
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
public UserController(Database database) {
|
||||
|
||||
public UserController(Database database)
|
||||
{
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("user/{username}")]
|
||||
public async Task<IActionResult> GetUser(string username) {
|
||||
public async Task<IActionResult> GetUser(string username)
|
||||
{
|
||||
User user = await this.database.Users
|
||||
.Include(u => u.Location)
|
||||
.FirstOrDefaultAsync(u => u.Username == username);
|
||||
|
||||
if(user == null) return this.NotFound();
|
||||
if (user == null) return this.NotFound();
|
||||
return this.Ok(user.Serialize());
|
||||
}
|
||||
|
||||
[HttpGet("user/{username}/playlists")]
|
||||
public async Task<IActionResult> GetUserPlaylists(string username)
|
||||
{
|
||||
return this.Ok();
|
||||
}
|
||||
|
||||
// [HttpPost("user/{username}")]
|
||||
// public async Task<IActionResult> CreateUser(string username) {
|
||||
// await new Database().CreateUser(username);
|
||||
|
@ -35,12 +46,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
// }
|
||||
|
||||
[HttpPost("updateUser")]
|
||||
public async Task<IActionResult> UpdateUser() {
|
||||
public async Task<IActionResult> UpdateUser()
|
||||
{
|
||||
User user = await this.database.UserFromRequest(this.Request);
|
||||
|
||||
if(user == null) return this.StatusCode(403, "");
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
XmlReaderSettings settings = new() {
|
||||
XmlReaderSettings settings = new()
|
||||
{
|
||||
Async = true, // this is apparently not default
|
||||
};
|
||||
|
||||
|
@ -62,39 +75,57 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
// </updateUser>
|
||||
//
|
||||
// if you find a way to make it not stupid feel free to replace this
|
||||
using(XmlReader reader = XmlReader.Create(this.Request.Body, settings)) {
|
||||
List<string> path = new(); // you can think of this as a file path in the XML, like <updateUser> -> <location> -> <x>
|
||||
while(await reader.ReadAsync()) {
|
||||
using (XmlReader reader = XmlReader.Create(this.Request.Body, settings))
|
||||
{
|
||||
List<string>
|
||||
path = new(); // you can think of this as a file path in the XML, like <updateUser> -> <location> -> <x>
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
|
||||
switch(reader.NodeType) {
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element:
|
||||
path.Add(reader.Name);
|
||||
break;
|
||||
case XmlNodeType.Text:
|
||||
switch(path[1]) {
|
||||
case "biography": {
|
||||
switch (path[1])
|
||||
{
|
||||
case "biography":
|
||||
{
|
||||
user.Biography = await reader.GetValueAsync();
|
||||
break;
|
||||
}
|
||||
case "location": {
|
||||
locationChanged = true; // if we're here then we're probably about to change the location.
|
||||
case "location":
|
||||
{
|
||||
locationChanged =
|
||||
true; // if we're here then we're probably about to change the location.
|
||||
// ReSharper disable once ConvertIfStatementToSwitchStatement
|
||||
if(path[2] == "x") {
|
||||
user.Location.X = Convert.ToInt32(await reader.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
|
||||
} else if(path[2] == "y") {
|
||||
if (path[2] == "x")
|
||||
{
|
||||
user.Location.X =
|
||||
Convert.ToInt32(
|
||||
await reader
|
||||
.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
|
||||
}
|
||||
else if (path[2] == "y")
|
||||
{
|
||||
user.Location.Y = Convert.ToInt32(await reader.GetValueAsync());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case "icon": {
|
||||
case "icon":
|
||||
{
|
||||
user.IconHash = await reader.GetValueAsync();
|
||||
break;
|
||||
}
|
||||
case "planets": {
|
||||
case "planets":
|
||||
{
|
||||
user.PlanetHash = await reader.GetValueAsync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case XmlNodeType.EndElement:
|
||||
path.RemoveAt(path.Count - 1);
|
||||
|
@ -102,19 +133,23 @@ namespace LBPUnion.ProjectLighthouse.Controllers {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the way location on a user card works is stupid and will not save with the way below as-is, so we do the following:
|
||||
if(locationChanged) { // only modify the database if we modify here
|
||||
Location l = await this.database.Locations.Where(l => l.Id == user.LocationId).FirstOrDefaultAsync(); // find the location in the database again
|
||||
if (locationChanged)
|
||||
{
|
||||
// only modify the database if we modify here
|
||||
Location l = await this.database.Locations.Where(l => l.Id == user.LocationId)
|
||||
.FirstOrDefaultAsync(); // find the location in the database again
|
||||
|
||||
// set the location in the database to the one we modified above
|
||||
l.X = user.Location.X;
|
||||
l.Y = user.Location.Y;
|
||||
|
||||
|
||||
// now both are in sync, and will update in the database.
|
||||
}
|
||||
|
||||
if(this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
|
||||
|
||||
if (this.database.ChangeTracker.HasChanges())
|
||||
await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
|
||||
return this.Ok();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@ using LBPUnion.ProjectLighthouse.Types.Settings;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse {
|
||||
public class Database : DbContext {
|
||||
namespace LBPUnion.ProjectLighthouse
|
||||
{
|
||||
public class Database : DbContext
|
||||
{
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<Location> Locations { get; set; }
|
||||
public DbSet<Slot> Slots { get; set; }
|
||||
|
@ -26,16 +28,18 @@ namespace LBPUnion.ProjectLighthouse {
|
|||
MySqlServerVersion.LatestSupportedServerVersion
|
||||
);
|
||||
|
||||
public async Task<User> CreateUser(string username) {
|
||||
public async Task<User> CreateUser(string username)
|
||||
{
|
||||
User user;
|
||||
if((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null)
|
||||
if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null)
|
||||
return user;
|
||||
|
||||
Location l = new(); // store to get id after submitting
|
||||
this.Locations.Add(l); // add to table
|
||||
await this.SaveChangesAsync(); // saving to the database returns the id and sets it on this entity
|
||||
|
||||
user = new User {
|
||||
user = new User
|
||||
{
|
||||
Username = username,
|
||||
LocationId = l.Id,
|
||||
Biography = username + " hasn't introduced themselves yet.",
|
||||
|
@ -46,14 +50,16 @@ namespace LBPUnion.ProjectLighthouse {
|
|||
|
||||
return user;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
public async Task<Token?> AuthenticateUser(LoginData loginData) {
|
||||
|
||||
#nullable enable
|
||||
public async Task<Token?> AuthenticateUser(LoginData loginData)
|
||||
{
|
||||
// TODO: don't use psn name to authenticate
|
||||
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username)
|
||||
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username)
|
||||
?? await this.CreateUser(loginData.Username);
|
||||
|
||||
Token token = new() {
|
||||
Token token = new()
|
||||
{
|
||||
UserToken = HashHelper.GenerateAuthToken(),
|
||||
UserId = user.UserId,
|
||||
};
|
||||
|
@ -64,21 +70,24 @@ namespace LBPUnion.ProjectLighthouse {
|
|||
return token;
|
||||
}
|
||||
|
||||
public async Task<User?> UserFromAuthToken(string authToken) {
|
||||
public async Task<User?> UserFromAuthToken(string authToken)
|
||||
{
|
||||
Token? token = await this.Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
|
||||
if(token == null) return null;
|
||||
if (token == null) return null;
|
||||
return await this.Users
|
||||
.Include(u => u.Location)
|
||||
.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||
}
|
||||
|
||||
public async Task<User?> UserFromRequest(HttpRequest request) {
|
||||
if(!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) {
|
||||
public async Task<User?> UserFromRequest(HttpRequest request)
|
||||
{
|
||||
if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return await this.UserFromAuthToken(mmAuth);
|
||||
}
|
||||
#nullable disable
|
||||
#nullable disable
|
||||
}
|
||||
}
|
39
ProjectLighthouse/DigestUtils.cs
Normal file
39
ProjectLighthouse/DigestUtils.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse
|
||||
{
|
||||
public static class DigestUtils
|
||||
{
|
||||
public static async Task<string> ComputeDigest(string path, string authCookie, Stream body,
|
||||
string digestKey)
|
||||
{
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
var pathBytes = Encoding.UTF8.GetBytes(path);
|
||||
var cookieBytes = string.IsNullOrEmpty(authCookie)
|
||||
? Array.Empty<byte>()
|
||||
: Encoding.UTF8.GetBytes(authCookie);
|
||||
var keyBytes = Encoding.UTF8.GetBytes(digestKey);
|
||||
|
||||
await body.CopyToAsync(memoryStream);
|
||||
|
||||
var bodyBytes = memoryStream.ToArray();
|
||||
|
||||
using var sha1 = IncrementalHash.CreateHash(HashAlgorithmName.SHA1);
|
||||
sha1.AppendData(bodyBytes);
|
||||
if (cookieBytes.Length > 0)
|
||||
sha1.AppendData(cookieBytes);
|
||||
sha1.AppendData(pathBytes);
|
||||
sha1.AppendData(keyBytes);
|
||||
|
||||
var digestBytes = sha1.GetHashAndReset();
|
||||
var digestString = Convert.ToHexString(digestBytes).ToLower();
|
||||
|
||||
return digestString;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,9 @@ namespace LBPUnion.ProjectLighthouse.Logging {
|
|||
public class LighthouseFileLogger : LoggerBase {
|
||||
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
||||
|
||||
public override void Send(LoggerLine line) {
|
||||
public override void Send(LoggerLine line)
|
||||
{
|
||||
return;
|
||||
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
||||
|
||||
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel + ".log"), line.LineData + "\n");
|
||||
|
|
|
@ -10,51 +10,59 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse {
|
||||
public static class Program {
|
||||
public static void Main(string[] args) {
|
||||
namespace LBPUnion.ProjectLighthouse
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// Log startup time
|
||||
Stopwatch startupStopwatch = new();
|
||||
startupStopwatch.Start();
|
||||
|
||||
|
||||
// Setup logging
|
||||
|
||||
|
||||
Logger.StartLogging();
|
||||
LoggerLine.LogFormat = "[{0}] {1}";
|
||||
Logger.AddLogger(new ConsoleLogger());
|
||||
Logger.AddLogger(new LighthouseFileLogger());
|
||||
|
||||
|
||||
Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance);
|
||||
Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance);
|
||||
bool dbConnected = ServerSettings.DbConnected;
|
||||
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance);
|
||||
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.",
|
||||
LoggerLevelStartup.Instance);
|
||||
|
||||
if(dbConnected) {
|
||||
if (dbConnected)
|
||||
{
|
||||
Stopwatch migrationStopwatch = new();
|
||||
migrationStopwatch.Start();
|
||||
|
||||
|
||||
Logger.Log("Migrating database...", LoggerLevelDatabase.Instance);
|
||||
using Database database = new();
|
||||
database.Database.Migrate();
|
||||
|
||||
|
||||
migrationStopwatch.Stop();
|
||||
Logger.Log($"Migration took {migrationStopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance);
|
||||
} else Environment.Exit(1);
|
||||
|
||||
}
|
||||
else Environment.Exit(1);
|
||||
|
||||
startupStopwatch.Stop();
|
||||
Logger.Log($"Ready! Startup took {startupStopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance);
|
||||
Logger.Log(
|
||||
$"Ready! Startup took {startupStopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...",
|
||||
LoggerLevelStartup.Instance);
|
||||
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder => {
|
||||
webBuilder.UseStartup<Startup>();
|
||||
})
|
||||
.ConfigureLogging(logging => {
|
||||
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); })
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>());
|
||||
logging.Services.TryAddEnumerable(ServiceDescriptor
|
||||
.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
|
@ -9,48 +12,115 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse {
|
||||
public class Startup {
|
||||
public Startup(IConfiguration configuration) {
|
||||
namespace LBPUnion.ProjectLighthouse
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
this.Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services) {
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
services.AddMvc(options =>
|
||||
options.OutputFormatters.Add(new XmlOutputFormatter()));
|
||||
|
||||
|
||||
services.AddDbContext<Database>();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
|
||||
if(env.IsDevelopment()) {
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
var computeDigests = true;
|
||||
var serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY");
|
||||
if (string.IsNullOrWhiteSpace(serverDigestKey))
|
||||
{
|
||||
Logger.Log(
|
||||
"SERVER_DIGEST_KEY environment variable wasn't set, so server digest headers won't be set. This will break LBP 1 and LBP 3."
|
||||
);
|
||||
computeDigests = false;
|
||||
}
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
// 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) => {
|
||||
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
|
||||
|
||||
// Client digest check.
|
||||
var authCookie = null as string;
|
||||
if (!context.Request.Cookies.TryGetValue("MM_AUTH", out authCookie))
|
||||
authCookie = string.Empty;
|
||||
if (context.Request.Headers.TryGetValue("X-Digest-A", out var clientDigest))
|
||||
{
|
||||
var digestPath = context.Request.Path;
|
||||
var body = context.Request.Body;
|
||||
|
||||
var digest = await DigestUtils.ComputeDigest(digestPath, authCookie, body, serverDigestKey);
|
||||
|
||||
if (digest != clientDigest)
|
||||
{
|
||||
Logger.Log($"Client digest {clientDigest} does not match server digest {digest}.");
|
||||
context.Abort();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Headers.Add("X-Digest-B", digest);
|
||||
context.Request.Body.Position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This does the same as above, but for the response stream.
|
||||
using var responseBuffer = new MemoryStream();
|
||||
var oldResponseStream = context.Response.Body;
|
||||
context.Response.Body = responseBuffer;
|
||||
|
||||
await next(); // Handle the request so we can get the status code from it
|
||||
|
||||
// Compute the server digest hash.
|
||||
if (computeDigests && context.Request.Headers.TryGetValue("X-Digest-A", out var a))
|
||||
{
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
// Compute the digest for the response.
|
||||
var serverDigest = await DigestUtils.ComputeDigest(context.Request.Path, authCookie,
|
||||
responseBuffer, serverDigestKey);
|
||||
context.Response.Headers.Add("X-Digest-A", serverDigest);
|
||||
}
|
||||
|
||||
// Copy the buffered response to the actual respose stream.
|
||||
responseBuffer.Position = 0;
|
||||
|
||||
await responseBuffer.CopyToAsync(oldResponseStream);
|
||||
|
||||
context.Response.Body = oldResponseStream;
|
||||
|
||||
requestStopwatch.Stop();
|
||||
|
||||
|
||||
Logger.Log(
|
||||
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
||||
LoggerLevelHttp.Instance
|
||||
);
|
||||
|
||||
if(context.Request.Method == "POST") {
|
||||
|
||||
if (context.Request.Method == "POST")
|
||||
{
|
||||
context.Request.Body.Position = 0;
|
||||
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
||||
}
|
||||
|
@ -58,9 +128,7 @@ namespace LBPUnion.ProjectLighthouse {
|
|||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseEndpoints(endpoints => {
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue