mirror of https://github.com/icedream/npsharp.git
Introducing user numbers (not generated from Brightstar entity identifiers anymore) and using partial database class methods instead to keep the code properly managed
parent
f43f20522f
commit
f30839d297
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using log4net;
|
||||
|
@ -26,25 +27,28 @@ namespace NPSharp.CommandLine.Server
|
|||
|
||||
public AuthenticationResult AuthenticateUser(NPServerClient client, string token)
|
||||
{
|
||||
var ar = new AuthenticationResult();
|
||||
|
||||
// Check if token is valid
|
||||
var resultEnum = _db.Sessions.Where(s => s.Id == token && s.ExpiryTime > DateTime.Now);
|
||||
if (!resultEnum.Any())
|
||||
return new AuthenticationResult(); // authentication failed because token is invalid
|
||||
_db.ValidateSession(token, session =>
|
||||
{
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var session = resultEnum.Single();
|
||||
|
||||
var ar =
|
||||
ar =
|
||||
new AuthenticationResult(new CSteamID
|
||||
{
|
||||
AccountID = uint.Parse(session.User.Id, NumberStyles.Integer),
|
||||
AccountID = session.User.UserNumber,
|
||||
AccountInstance = 1,
|
||||
AccountType = EAccountType.Individual,
|
||||
AccountUniverse = EUniverse.Public
|
||||
});
|
||||
|
||||
_db.DeleteObject(session);
|
||||
_log.DebugFormat("Deleting validated session {0}", session.Id);
|
||||
});
|
||||
_db.SaveChanges();
|
||||
_log.DebugFormat("Deleted now used session {0}", session.Id);
|
||||
|
||||
return ar;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,11 @@
|
|||
// -----------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated from a template.
|
||||
//
|
||||
// Changes to this file may cause incorrect behaviour and will be lost
|
||||
// if the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BrightstarDB.Client;
|
||||
using BrightstarDB.EntityFramework;
|
||||
|
||||
namespace NPSharp.CommandLine.Server.Database
|
||||
{
|
||||
public class BrightstarDatabaseContext : BrightstarEntityContext
|
||||
public partial class BrightstarDatabaseContext : BrightstarEntityContext
|
||||
{
|
||||
private static readonly EntityMappingStore TypeMappings;
|
||||
|
||||
|
@ -392,6 +383,12 @@ namespace NPSharp.CommandLine.Server.Database
|
|||
set { SetRelatedProperty("UserMail", value); }
|
||||
}
|
||||
|
||||
public UInt32 UserNumber
|
||||
{
|
||||
get { return GetRelatedProperty<UInt32>("UserNumber"); }
|
||||
set { SetRelatedProperty("UserNumber", value); }
|
||||
}
|
||||
|
||||
public String PasswordHash
|
||||
{
|
||||
get { return GetRelatedProperty<String>("PasswordHash"); }
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NPSharp.CommandLine.Server.Database
|
||||
{
|
||||
public partial class BrightstarDatabaseContext
|
||||
{
|
||||
public IUser CreateUser(string name, string email, string password)
|
||||
{
|
||||
if (UserExists(name))
|
||||
throw new DatabaseUserExistsException();
|
||||
|
||||
var user = Users.Create();
|
||||
user.UserName = name;
|
||||
user.UserMail = email;
|
||||
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(password);
|
||||
user.UserNumber = _genUserNumber(/*user.Id*/);
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private uint _genUserNumber(/*string userId*/)
|
||||
{
|
||||
/*
|
||||
// for some reason we sometimes get full URIs here.
|
||||
userId = userId.Split('/').Last().Replace("-", "");
|
||||
|
||||
// Since the string is a hexified UNIQUE identifier,
|
||||
// use the numeric representation of it.
|
||||
var userNum = uint.Parse(userId, NumberStyles.HexNumber);
|
||||
*/
|
||||
|
||||
// The above doesn't work since the GUID has a few bits too much :P
|
||||
// So instead - even though taking more queries - we will use the user
|
||||
// count to approximate a new user ID.
|
||||
var userNum = (uint)Users.Count() + 1;
|
||||
while (Users.Count(u => u.UserNumber == userNum) > 0)
|
||||
userNum++;
|
||||
|
||||
return userNum;
|
||||
}
|
||||
|
||||
public bool UserExists(string userName)
|
||||
{
|
||||
return GetUser(userName) != null;
|
||||
}
|
||||
|
||||
public IUser GetUser(string userName)
|
||||
{
|
||||
var users = Users.Where(u => u.UserName == userName).ToArray();
|
||||
return users.Any() ? users.Single() : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a user session.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to assign the session to.</param>
|
||||
/// <param name="validTimeSpan">The time span in seconds. Default: 3 minutes.</param>
|
||||
/// <returns>The newly created user session</returns>
|
||||
public ISession CreateSession(IUser user, uint validTimeSpan = 3 * 60)
|
||||
{
|
||||
var session = Sessions.Create();
|
||||
session.ExpiryTime = DateTime.Now + TimeSpan.FromSeconds(validTimeSpan);
|
||||
|
||||
user.Sessions.Add(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find the wanted session and drops it if it's valid,
|
||||
/// therefore "using it".
|
||||
/// </summary>
|
||||
/// <param name="sessionToken">The token of the wanted session</param>
|
||||
/// <param name="callback">The callback to use for session results (goes for both invalid and valid sessions)</param>
|
||||
/// <returns>The found session if the session is validated successfully, otherwise null.</returns>
|
||||
public void ValidateSession(string sessionToken, Action<ISession> callback)
|
||||
{
|
||||
var sessions = Sessions
|
||||
.Where(s => s.Id == sessionToken).ToArray() // database level query
|
||||
.Where(s => s.ExpiryTime > DateTime.Now).ToArray(); // local level query (seems like this isn't supported [yet])
|
||||
|
||||
// We have to use a callback here since deleting the object from database
|
||||
// will also release it from .NET's management and therefore makes the object
|
||||
// invalid.
|
||||
if (!sessions.Any())
|
||||
callback(null);
|
||||
else
|
||||
{
|
||||
var session = sessions.Single();
|
||||
callback(session);
|
||||
DeleteObject(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
using System;
|
||||
|
||||
namespace NPSharp.CommandLine.Server.Database
|
||||
{
|
||||
class DatabaseUserExistsException : Exception
|
||||
{
|
||||
}
|
||||
}
|
|
@ -13,6 +13,8 @@ namespace NPSharp.CommandLine.Server.Database
|
|||
|
||||
string UserMail { get; set; }
|
||||
|
||||
uint UserNumber { get; set; }
|
||||
|
||||
string PasswordHash { get; set; }
|
||||
|
||||
DateTime LastLogin { get; set; }
|
||||
|
|
|
@ -33,7 +33,6 @@ namespace NPSharp.CommandLine.Server
|
|||
|
||||
private static BrightstarDatabaseContext OpenDatabase(string store = "NP")
|
||||
{
|
||||
// TODO: This line is CREATING a new database but it's supposed to open it only if it's already created. Look up!
|
||||
return
|
||||
new BrightstarDatabaseContext(
|
||||
"type=embedded;storesdirectory=Database\\;storename=" + store,
|
||||
|
@ -53,21 +52,16 @@ namespace NPSharp.CommandLine.Server
|
|||
if (db.Users.Count() > 0)
|
||||
return;
|
||||
|
||||
// Create first user (test:test)
|
||||
var testUser = db.Users.Create();
|
||||
testUser.PasswordHash = BCrypt.Net.BCrypt.HashPassword("test");
|
||||
testUser.UserMail = "test@localhost";
|
||||
testUser.UserName = "test";
|
||||
// Create first user
|
||||
var testUser = db.CreateUser("test", "test@localhost", "test");
|
||||
db.SaveChanges();
|
||||
|
||||
_log.InfoFormat(
|
||||
"Created first user with following details:" + Environment.NewLine + Environment.NewLine +
|
||||
"Username: {0}" + Environment.NewLine + "Password: {1}",
|
||||
"Username: {0}" + Environment.NewLine +
|
||||
"Password: {1}" + Environment.NewLine,
|
||||
testUser.UserName,
|
||||
"test");
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
_log.DebugFormat("First user id is {0}", testUser.Id);
|
||||
}
|
||||
|
||||
// Cleanup thread
|
||||
|
@ -78,11 +72,13 @@ namespace NPSharp.CommandLine.Server
|
|||
using (var dbForCleanup = OpenDatabase())
|
||||
{
|
||||
_log.Debug("Starting cleanup...");
|
||||
|
||||
foreach (var session in dbForCleanup.Sessions.Where(s => s.ExpiryTime < DateTime.Now).ToArray())
|
||||
{
|
||||
_log.DebugFormat("Session {0} became invalid", session.Id);
|
||||
dbForCleanup.DeleteObject(session);
|
||||
}
|
||||
|
||||
foreach (var ban in dbForCleanup.Bans.Where(s => s.ExpiryTime < DateTime.Now).ToArray())
|
||||
{
|
||||
_log.DebugFormat("Ban {0} became invalid", ban.Id);
|
||||
|
@ -95,7 +91,6 @@ namespace NPSharp.CommandLine.Server
|
|||
dbForCleanup.DeleteObject(cheatDetection);
|
||||
}
|
||||
|
||||
_log.Debug("Saving cleanup...");
|
||||
dbForCleanup.SaveChanges();
|
||||
|
||||
_log.Debug("Cleanup done.");
|
||||
|
@ -117,16 +112,12 @@ namespace NPSharp.CommandLine.Server
|
|||
{
|
||||
using (var db = OpenDatabase())
|
||||
{
|
||||
var matchingUsers =
|
||||
db.Users.Where(u => u.UserName == loginUsername).ToArray() // brightstar level
|
||||
.Where(u => BCrypt.Net.BCrypt.Verify(loginPassword, u.PasswordHash)).ToArray() // local level
|
||||
;
|
||||
var user = db.GetUser(loginUsername);
|
||||
|
||||
if (!matchingUsers.Any())
|
||||
|
||||
if (user == null || !BCrypt.Net.BCrypt.Verify(loginPassword, user.PasswordHash))
|
||||
return new SessionAuthenticationResult {Reason = "Invalid credentials"};
|
||||
|
||||
var user = matchingUsers.Single();
|
||||
|
||||
// Check for bans
|
||||
var bans = user.Bans.Where(b => b.ExpiryTime > DateTime.Now).ToArray();
|
||||
if (bans.Any())
|
||||
|
@ -153,9 +144,8 @@ namespace NPSharp.CommandLine.Server
|
|||
}
|
||||
|
||||
// Create user session
|
||||
var session = db.Sessions.Create();
|
||||
session.ExpiryTime = DateTime.Now + TimeSpan.FromMinutes(3);
|
||||
user.Sessions.Add(session);
|
||||
var session = db.CreateSession(user);
|
||||
_log.DebugFormat("Created session {0}", session.Id);
|
||||
|
||||
// Update user's last login data
|
||||
user.LastLogin = DateTime.Now;
|
||||
|
@ -168,7 +158,7 @@ namespace NPSharp.CommandLine.Server
|
|||
{
|
||||
Success = true,
|
||||
SessionToken = session.Id,
|
||||
UserID = uint.Parse(user.Id, NumberStyles.Integer),
|
||||
UserID = user.UserNumber,
|
||||
UserMail = user.UserMail,
|
||||
UserName = user.UserName
|
||||
};
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Database\BrightstarDatabaseContext.custom.cs" />
|
||||
<Compile Include="Database\DatabaseUserExistsException.cs" />
|
||||
<Compile Include="Database\IBan.cs" />
|
||||
<Compile Include="Database\ICheatDetection.cs" />
|
||||
<Compile Include="Database\IFriend.cs" />
|
||||
|
|
Loading…
Reference in New Issue