massive checkpoint

This commit is contained in:
2021-09-03 22:43:06 -05:00
parent bb1d2c491c
commit 2a3b7b32b4
40 changed files with 456 additions and 738 deletions

View File

@@ -1,7 +1,9 @@
using Gameboard.ShogiUI.Sockets.Managers;
using Gameboard.ShogiUI.Sockets.Extensions;
using Gameboard.ShogiUI.Sockets.Managers;
using Gameboard.ShogiUI.Sockets.Repositories;
using Gameboard.ShogiUI.Sockets.ServiceModels.Api;
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket;
using Gameboard.ShogiUI.Sockets.ServiceModels.Types;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
@@ -10,16 +12,15 @@ using System.Threading.Tasks;
namespace Gameboard.ShogiUI.Sockets.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
[Authorize(Roles = "Shogi")]
public class GameController : ControllerBase
{
private static readonly string UsernameClaim = "preferred_username";
private readonly IGameboardManager gameboardManager;
private readonly IGameboardRepository gameboardRepository;
private readonly ISocketConnectionManager communicationManager;
private string? JwtUserName => HttpContext.User.Claims.FirstOrDefault(c => c.Type == UsernameClaim)?.Value;
public GameController(
IGameboardRepository repository,
@@ -68,22 +69,12 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
[HttpPost("{gameName}/Move")]
public async Task<IActionResult> PostMove([FromRoute] string gameName, [FromBody] PostMove request)
{
Models.User? user = null;
if (Request.Cookies.ContainsKey(SocketController.WebSessionKey))
{
var webSessionId = Guid.Parse(Request.Cookies[SocketController.WebSessionKey]!);
user = await gameboardManager.ReadUser(webSessionId);
}
else if (!string.IsNullOrEmpty(JwtUserName))
{
user = await gameboardManager.ReadUser(JwtUserName);
}
var session = await gameboardManager.ReadSession(gameName);
var user = await gameboardManager.ReadUser(User);
var session = await gameboardRepository.ReadSession(gameName);
if (session == null || user == null || (session.Player1 != user.Name && session.Player2 != user.Name))
{
throw new UnauthorizedAccessException("You are not seated at this game.");
throw new UnauthorizedAccessException("User is not seated at this game.");
}
var move = request.Move;
@@ -94,13 +85,19 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
if (moveSuccess)
{
var createSuccess = await gameboardRepository.CreateBoardState(session);
if (!createSuccess)
{
throw new ApplicationException("Unable to persist board state.");
}
await communicationManager.BroadcastToPlayers(new MoveResponse
{
GameName = session.Name,
PlayerName = user.Name,
Move = moveModel.ToServiceModel()
BoardState = session.Shogi.ToServiceModel(),
Game = session.ToServiceModel(),
MoveHistory = session.Shogi.MoveHistory.Select(h => h.ToServiceModel()).ToList(),
PlayerPerspective = user.Name == session.Player1 ? WhichPlayer.Player1 : WhichPlayer.Player2
}, session.Player1, session.Player2);
return Created(string.Empty, null);
return Ok();
}
throw new InvalidOperationException("Illegal move.");
}
@@ -124,5 +121,56 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
// }
// return new ConflictResult();
//}
[HttpPost]
public async Task<IActionResult> PostSession([FromBody] PostSession request)
{
var user = await gameboardManager.ReadUser(User);
var session = new Models.SessionMetadata(request.Name, request.IsPrivate, user!.Name);
var success = await gameboardRepository.CreateSession(session);
if (success)
{
await communicationManager.BroadcastToAll(new CreateGameResponse
{
Game = session.ToServiceModel(),
PlayerName = user.Name
});
return Ok();
}
return Conflict();
}
/// <summary>
/// Reads the board session and subscribes the caller to socket events for that session.
/// </summary>
[HttpGet("{gameName}")]
public async Task<IActionResult> GetSession([FromRoute] string gameName)
{
var user = await gameboardManager.ReadUser(User);
var session = await gameboardRepository.ReadSession(gameName);
if (session == null)
{
return NotFound();
}
communicationManager.SubscribeToGame(session, user!.Name);
var response = new GetGameResponse()
{
Game = new Models.SessionMetadata(session).ToServiceModel(),
BoardState = session.Shogi.ToServiceModel(),
MoveHistory = session.Shogi.MoveHistory.Select(_ => _.ToServiceModel()).ToList(),
PlayerPerspective = user.Name == session.Player1 ? WhichPlayer.Player1 : WhichPlayer.Player2
};
return new JsonResult(response);
}
[HttpGet]
public async Task<IActionResult> GetSessions()
{
var sessions = await gameboardRepository.ReadSessionMetadatas();
return new JsonResult(sessions.Select(s => s.ToServiceModel()).ToList());
}
}
}

View File

@@ -1,96 +1,113 @@
using Gameboard.ShogiUI.Sockets.Managers;
using Gameboard.ShogiUI.Sockets.Extensions;
using Gameboard.ShogiUI.Sockets.Managers;
using Gameboard.ShogiUI.Sockets.Models;
using Gameboard.ShogiUI.Sockets.Repositories;
using Gameboard.ShogiUI.Sockets.ServiceModels.Api;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Gameboard.ShogiUI.Sockets.Controllers
{
[Authorize]
[Route("[controller]")]
[ApiController]
[Route("[controller]")]
[Authorize(Roles = "Shogi")]
public class SocketController : ControllerBase
{
public static readonly string WebSessionKey = "session-id";
private readonly ILogger<SocketController> logger;
private readonly ISocketTokenManager tokenManager;
private readonly ISocketTokenCache tokenCache;
private readonly IGameboardManager gameboardManager;
private readonly IGameboardRepository gameboardRepository;
private readonly CookieOptions createSessionOptions;
private readonly CookieOptions deleteSessionOptions;
private readonly AuthenticationProperties authenticationProps;
public SocketController(
ILogger<SocketController> logger,
ISocketTokenManager tokenManager,
ISocketTokenCache tokenCache,
IGameboardManager gameboardManager,
IGameboardRepository gameboardRepository)
{
this.logger = logger;
this.tokenManager = tokenManager;
this.tokenCache = tokenCache;
this.gameboardManager = gameboardManager;
this.gameboardRepository = gameboardRepository;
createSessionOptions = new CookieOptions
authenticationProps = new AuthenticationProperties
{
Secure = true,
HttpOnly = true,
SameSite = SameSiteMode.None,
Expires = DateTimeOffset.Now.AddYears(5)
AllowRefresh = true,
IsPersistent = true
};
deleteSessionOptions = new CookieOptions();
}
[HttpGet("Yep")]
[HttpGet("GuestLogout")]
[AllowAnonymous]
public IActionResult Yep()
public async Task<IActionResult> GuestLogout()
{
deleteSessionOptions.Expires = DateTimeOffset.Now.AddDays(-1);
Response.Cookies.Append(WebSessionKey, "", deleteSessionOptions);
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Ok();
}
[HttpGet("Token")]
public IActionResult GetToken()
public async Task<IActionResult> GetToken()
{
var userName = HttpContext.User.Claims.First(c => c.Type == "preferred_username").Value;
var token = tokenManager.GenerateToken(userName);
var identityId = User.UserId();
if (string.IsNullOrWhiteSpace(identityId))
{
return Unauthorized();
}
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
user = new User(identityId);
var success = await gameboardRepository.CreateUser(user);
if (!success)
{
return Unauthorized();
}
}
var token = tokenCache.GenerateToken(user.Name);
return new JsonResult(new GetTokenResponse(token));
}
/// <summary>
/// Builds a token for guest users to send when requesting a socket connection.
/// Sends a HttpOnly cookie to the client with which to identify guest users.
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpGet("GuestToken")]
[AllowAnonymous]
public async Task<IActionResult> GetGuestToken()
{
var cookies = Request.Cookies;
var webSessionId = cookies.ContainsKey(WebSessionKey)
? Guid.Parse(cookies[WebSessionKey]!)
: Guid.NewGuid();
var webSessionIdAsString = webSessionId.ToString();
var user = await gameboardRepository.ReadGuestUser(webSessionId);
if (user == null)
if (Guid.TryParse(User.UserId(), out Guid webSessionId))
{
var userName = await gameboardManager.CreateGuestUser(webSessionId);
var token = tokenManager.GenerateToken(webSessionIdAsString);
Response.Cookies.Append(WebSessionKey, webSessionIdAsString, createSessionOptions);
return new JsonResult(new GetGuestTokenResponse(userName, token));
var user = await gameboardRepository.ReadGuestUser(webSessionId);
if (user != null)
{
var token = tokenCache.GenerateToken(webSessionId.ToString());
return new JsonResult(new GetGuestTokenResponse(user.Name, token));
}
}
else
{
var token = tokenManager.GenerateToken(webSessionIdAsString);
Response.Cookies.Append(WebSessionKey, webSessionIdAsString, createSessionOptions);
return new JsonResult(new GetGuestTokenResponse(user.Name, token));
// Setup a guest user.
var newSessionId = Guid.NewGuid();
var user = new User(Guid.NewGuid().ToString(), newSessionId);
if (await gameboardRepository.CreateUser(user))
{
var identity = user.CreateGuestUserIdentity();
await this.HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(identity),
authenticationProps
);
var token = tokenCache.GenerateToken(newSessionId.ToString());
return new JsonResult(new GetGuestTokenResponse(user.Name, token));
}
}
return Unauthorized();
}
}
}