add support for account login

This commit is contained in:
Elijah R 2024-04-07 15:53:27 -04:00
parent 103bad27b6
commit 7117823772
3 changed files with 64 additions and 5 deletions

View file

@ -0,0 +1,7 @@
namespace CollabVMSharp;
public class AccountLoginResult
{
public bool Success { get; set; }
public string? Error { get; set; }
}

View file

@ -41,11 +41,13 @@ public class CollabVMClient {
private WebProxy? _proxy;
private Dictionary<string, Action<string, string[]>> commandsSeparatedArgs;
private Dictionary<string, Action<string, string>> commandsOneArg;
private bool _usesAccountAuth;
// Tasks and related
private TaskCompletionSource<Node[]> GotNodeList;
private TaskCompletionSource<bool> GotConnectionToNode;
private TaskCompletionSource<int> GotTurn;
private TaskCompletionSource<Rank> GotStaff;
private TaskCompletionSource<AccountLoginResult> LoginResult;
private List<GetIPTask> GotIPTasks;
private SemaphoreSlim QEMUMonitorSemaphore;
private TaskCompletionSource<string> QEMUMonitorResult;
@ -61,6 +63,7 @@ public class CollabVMClient {
public string Node { get { return this.node; } }
public string Username { get { return this.username; } }
public bool UsesAccountAuth { get { return this._usesAccountAuth; } }
// Events
public event EventHandler<ChatMessage> Chat;
public event EventHandler<ChatMessage[]> ChatHistory;
@ -78,6 +81,10 @@ public class CollabVMClient {
public event EventHandler<TurnUpdateEventArgs> TurnUpdate;
public event EventHandler ConnectionClosed;
/// <summary>
/// Fired when the VM requires account authentication. The provided string is the authentication server base URL.
/// </summary>
public event EventHandler<string> VMUsesAccountAuth;
/// <summary>
/// Client for the CollabVM 1.x Server
/// </summary>
/// <param name="url">URL of the CollabVM Server to connect to (Should start with ws:// or wss://)</param>
@ -99,6 +106,7 @@ public class CollabVMClient {
this._perms = Permissions.None;
this._connected = false;
this._connectedToVM = false;
this._usesAccountAuth = false;
this.framebuffer = new Image<Rgba32>(1, 1);
this.socket = new();
this.socket.Options.AddSubProtocol("guacamole");
@ -126,6 +134,7 @@ public class CollabVMClient {
this.GotConnectionToNode = new();
this.GotTurn = new();
this.GotStaff = new();
this.LoginResult = new();
this.GotIPTasks = new();
this.QEMUMonitorResult = new();
this.QEMUMonitorSemaphore = new(1, 1);
@ -145,6 +154,7 @@ public class CollabVMClient {
VoteCooldown += delegate { };
TurnUpdate += delegate { };
ConnectionClosed += delegate { };
VMUsesAccountAuth += delegate { };
}
/// <summary>
/// Connect to the CollabVM Server
@ -162,11 +172,12 @@ public class CollabVMClient {
this.SendMsg(Guacutils.Encode("rename", this.username));
else
this.SendMsg(Guacutils.Encode("rename"));
if (this.node != null)
this.SendMsg(Guacutils.Encode("connect", this.node));
this.NOPRecieve.Start();
this.WebSocketLoop();
return;
if (this.node == null) return;
this.GotConnectionToNode = new();
this.SendMsg(Guacutils.Encode("connect", this.node));
await this.GotConnectionToNode.Task;
}
private async void WebSocketLoop() {
@ -305,7 +316,11 @@ public class CollabVMClient {
}
default: {
var user = _users.Find(u => u.Username == msgArr[2]);
// I've no clue why this check is now needed, this has never been a problem before, but now it's causing a NullReferenceException
if (user != null)
{
user.Username = msgArr[3];
}
this.UserRenamed.Invoke(this, new UserRenamedEventArgs {
OldName = msgArr[2],
NewName = msgArr[3],
@ -324,6 +339,7 @@ public class CollabVMClient {
Username = msgArr[i],
Rank = msgArr[i + 1] switch {
"0" => Rank.Unregistered,
"1" => Rank.Registered,
"2" => Rank.Admin,
"3" => Rank.Moderator,
_ => Rank.Unregistered
@ -411,6 +427,33 @@ public class CollabVMClient {
this.TurnUpdate.Invoke(this, this._currentturn );
break;
}
case "auth":
{
this._usesAccountAuth = true;
VMUsesAccountAuth.Invoke(this, msgArr[1]);
break;
}
case "login":
{
if (msgArr[1] == "1")
{
this._rank = Rank.Registered;
this.LoginResult.TrySetResult(new()
{
Success = true
});
}
else
{
this.LoginResult.TrySetResult(new()
{
Success = false,
Error = msgArr[2]
});
}
break;
}
case "admin": {
switch (msgArr[1]) {
case "0": {
@ -625,6 +668,7 @@ public class CollabVMClient {
/// <param name="password">Password to log in with</param>
/// <returns>The rank received</returns>
public async Task<Rank> Login(string password) {
if (this._usesAccountAuth) throw new InvalidOperationException("This VM requires account authentication. Use the LoginAccount method instead.");
this.GotStaff = new();
this.SendMsg(Guacutils.Encode("admin", "2", password));
return await this.GotStaff.Task;
@ -856,6 +900,13 @@ public class CollabVMClient {
else SendMsg(Guacutils.Encode("rename", newname));
}
public async Task<AccountLoginResult> LoginAccount(string token)
{
this.LoginResult = new();
this.SendMsg(Guacutils.Encode("login", token));
return await this.LoginResult.Task;
}
private void ProcessCommand(string username, string cmd) {
// I stole this from stackoverflow
var re = new Regex("(?<=\")[^\"]*(?=\")|[^\" ]+");

View file

@ -42,6 +42,7 @@ public class Permissions {
public enum Rank {
Unregistered = 0,
Registered = 1,
Moderator = 3,
Admin = 2
}