mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-12 21:02:27 +00:00
Refactor Database into DatabaseContext Moved into separate folder so it actually has a namespace instead sitting in the root
207 lines
No EOL
8 KiB
C#
207 lines
No EOL
8 KiB
C#
#nullable enable
|
|
using System.Net;
|
|
using LBPUnion.ProjectLighthouse.Configuration;
|
|
using LBPUnion.ProjectLighthouse.Database;
|
|
using LBPUnion.ProjectLighthouse.Extensions;
|
|
using LBPUnion.ProjectLighthouse.Helpers;
|
|
using LBPUnion.ProjectLighthouse.Logging;
|
|
using LBPUnion.ProjectLighthouse.Tickets;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("LITTLEBIGPLANETPS3_XML/login")]
|
|
[Produces("text/xml")]
|
|
public class LoginController : ControllerBase
|
|
{
|
|
private readonly DatabaseContext database;
|
|
|
|
public LoginController(DatabaseContext database)
|
|
{
|
|
this.database = database;
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Login()
|
|
{
|
|
MemoryStream ms = new();
|
|
await this.Request.Body.CopyToAsync(ms);
|
|
byte[] loginData = ms.ToArray();
|
|
|
|
NPTicket? npTicket;
|
|
try
|
|
{
|
|
npTicket = NPTicket.CreateFromBytes(loginData);
|
|
}
|
|
catch
|
|
{
|
|
npTicket = null;
|
|
}
|
|
|
|
if (npTicket == null)
|
|
{
|
|
Logger.Warn("npTicket was null, rejecting login", LogArea.Login);
|
|
return this.BadRequest();
|
|
}
|
|
|
|
IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
|
if (remoteIpAddress == null)
|
|
{
|
|
Logger.Warn("unable to determine ip, rejecting login", LogArea.Login);
|
|
return this.BadRequest();
|
|
}
|
|
|
|
string ipAddress = remoteIpAddress.ToString();
|
|
|
|
string? username = npTicket.Username;
|
|
|
|
if (username == null)
|
|
{
|
|
Logger.Warn("Unable to determine username, rejecting login", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
await this.database.RemoveExpiredTokens();
|
|
|
|
User? user;
|
|
|
|
switch (npTicket.Platform)
|
|
{
|
|
case Platform.RPCS3:
|
|
user = await this.database.Users.FirstOrDefaultAsync(u => u.LinkedRpcnId == npTicket.UserId);
|
|
break;
|
|
case Platform.PS3:
|
|
case Platform.Vita:
|
|
case Platform.UnitTest:
|
|
user = await this.database.Users.FirstOrDefaultAsync(u => u.LinkedPsnId == npTicket.UserId);
|
|
break;
|
|
case Platform.PSP:
|
|
case Platform.Unknown:
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
// If this user id hasn't been linked to any accounts
|
|
if (user == null)
|
|
{
|
|
// Check if there is an account with that username already
|
|
User? targetUsername = await this.database.Users.FirstOrDefaultAsync(u => u.Username == npTicket.Username);
|
|
if (targetUsername != null)
|
|
{
|
|
ulong targetPlatform = npTicket.Platform == Platform.RPCS3
|
|
? targetUsername.LinkedRpcnId
|
|
: targetUsername.LinkedPsnId;
|
|
|
|
// only make a link request if the user doesn't already have an account linked for that platform
|
|
if (targetPlatform != 0)
|
|
{
|
|
Logger.Warn($"New user tried to login but their name is already taken, username={username}", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
// if there is already a pending link request don't create another
|
|
bool linkAttemptExists = await this.database.PlatformLinkAttempts.AnyAsync(p =>
|
|
p.Platform == npTicket.Platform &&
|
|
p.PlatformId == npTicket.UserId &&
|
|
p.UserId == targetUsername.UserId);
|
|
|
|
if (linkAttemptExists) return this.StatusCode(403, "");
|
|
|
|
PlatformLinkAttempt linkAttempt = new()
|
|
{
|
|
Platform = npTicket.Platform,
|
|
UserId = targetUsername.UserId,
|
|
IPAddress = ipAddress,
|
|
Timestamp = TimeHelper.TimestampMillis,
|
|
PlatformId = npTicket.UserId,
|
|
};
|
|
this.database.PlatformLinkAttempts.Add(linkAttempt);
|
|
await this.database.SaveChangesAsync();
|
|
Logger.Success($"User '{npTicket.Username}' tried to login but platform isn't linked, platform={npTicket.Platform}", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
if (!ServerConfiguration.Instance.Authentication.AutomaticAccountCreation)
|
|
{
|
|
Logger.Warn($"Unknown user tried to connect username={username}", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
// create account for user if they don't exist
|
|
user = await this.database.CreateUser(username, "$");
|
|
user.Password = null;
|
|
user.LinkedRpcnId = npTicket.Platform == Platform.RPCS3 ? npTicket.UserId : 0;
|
|
user.LinkedPsnId = npTicket.Platform != Platform.RPCS3 ? npTicket.UserId : 0;
|
|
await this.database.SaveChangesAsync();
|
|
|
|
Logger.Success($"Created new user for {username}, platform={npTicket.Platform}", LogArea.Login);
|
|
}
|
|
// automatically change username if it doesn't match
|
|
else if (user.Username != npTicket.Username)
|
|
{
|
|
bool usernameExists = await this.database.Users.AnyAsync(u => u.Username == npTicket.Username);
|
|
if (usernameExists)
|
|
{
|
|
Logger.Warn($"{npTicket.Platform} user changed their name to a name that is already taken," +
|
|
$" oldName='{user.Username}', newName='{npTicket.Username}'", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
Logger.Info($"User's username has changed, old='{user.Username}', new='{npTicket.Username}', platform={npTicket.Platform}", LogArea.Login);
|
|
user.Username = username;
|
|
this.database.PlatformLinkAttempts.RemoveWhere(p => p.UserId == user.UserId);
|
|
// unlink other platforms because the names no longer match
|
|
if (npTicket.Platform == Platform.RPCS3)
|
|
user.LinkedPsnId = 0;
|
|
else
|
|
user.LinkedRpcnId = 0;
|
|
|
|
await this.database.SaveChangesAsync();
|
|
}
|
|
|
|
GameToken? token = await this.database.GameTokens.Include(t => t.User)
|
|
.FirstOrDefaultAsync(t => t.UserLocation == ipAddress && t.User.Username == npTicket.Username && t.TicketHash == npTicket.TicketHash);
|
|
|
|
if (token != null)
|
|
{
|
|
Logger.Warn($"Rejecting duplicate ticket from {username}", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
token = await this.database.AuthenticateUser(user, npTicket, ipAddress);
|
|
if (token == null)
|
|
{
|
|
Logger.Warn($"Unable to find/generate a token for username {npTicket.Username}", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
if (user.IsBanned)
|
|
{
|
|
Logger.Error($"User {npTicket.Username} tried to login but is banned", LogArea.Login);
|
|
return this.StatusCode(403, "");
|
|
}
|
|
|
|
Logger.Success($"Successfully logged in user {user.Username} as {token.GameVersion} client", LogArea.Login);
|
|
|
|
user.LastLogin = TimeHelper.TimestampMillis;
|
|
|
|
await this.database.SaveChangesAsync();
|
|
|
|
// Create a new room on LBP2/3/Vita
|
|
if (token.GameVersion != GameVersion.LittleBigPlanet1) RoomHelper.CreateRoom(user.UserId, token.GameVersion, token.Platform);
|
|
|
|
return this.Ok
|
|
(
|
|
new LoginResult
|
|
{
|
|
AuthTicket = "MM_AUTH=" + token.UserToken,
|
|
ServerBrand = VersionHelper.EnvVer,
|
|
TitleStorageUrl = ServerConfiguration.Instance.GameApiExternalUrl,
|
|
}.Serialize()
|
|
);
|
|
}
|
|
} |