From 681377c4ad60ccf2a331fb42a325cd2a89683aab Mon Sep 17 00:00:00 2001 From: erri120 Date: Thu, 12 Sep 2024 14:18:25 +0200 Subject: [PATCH] Fix exception on cached value --- .../Auth/JWTToken.cs | 53 +++++++++---------- .../Auth/OAuth2MessageFactory.cs | 26 +++------ .../LoginManager.cs | 2 +- 3 files changed, 33 insertions(+), 48 deletions(-) diff --git a/src/Networking/NexusMods.Networking.NexusWebApi/Auth/JWTToken.cs b/src/Networking/NexusMods.Networking.NexusWebApi/Auth/JWTToken.cs index 6619a08b9b..3fc12123fb 100644 --- a/src/Networking/NexusMods.Networking.NexusWebApi/Auth/JWTToken.cs +++ b/src/Networking/NexusMods.Networking.NexusWebApi/Auth/JWTToken.cs @@ -1,10 +1,8 @@ -using System.Diagnostics.CodeAnalysis; +using DynamicData.Kernel; using NexusMods.Abstractions.NexusWebApi.DTOs.OAuth; using NexusMods.MnemonicDB.Abstractions; using NexusMods.MnemonicDB.Abstractions.Attributes; using NexusMods.MnemonicDB.Abstractions.Models; -using NexusMods.MnemonicDB.Abstractions.TxFunctions; -using File = NexusMods.Abstractions.Loadouts.Files.File; namespace NexusMods.Networking.NexusWebApi.Auth; @@ -29,49 +27,50 @@ public partial class JWTToken : IModelDefinition /// The date at which the token expires /// public static readonly TimestampAttribute ExpiresAt = new(Namespace, nameof(ExpiresAt)); - - + + private static Optional GetEntityId(IDb db) + { + var datoms = db.Datoms(PrimaryAttribute); + return datoms.Count == 0 ? Optional.None : datoms[0].E; + } + /// /// Try to find the JWT Token in the database. /// public static bool TryFind(IDb db, out ReadOnly token) { - var found = All(db).FirstOrDefault(); - if (found.IsValid()) + var entityId = GetEntityId(db); + if (!entityId.HasValue) { - token = found; - return true; + token = default(ReadOnly); + return false; } - - token = default(ReadOnly); - return false; + + token = Load(db, entityId.Value); + return token.IsValid(); } - - + /// /// Creates a new JWT Token model from a . And reuses the existing /// database id if it exists, as this data is a singleton. /// - public static EntityId? Create(IDb db, ITransaction tx, JwtTokenReply reply) + public static Optional Create(IDb db, ITransaction tx, JwtTokenReply reply) { - if (reply.AccessToken is null || reply.RefreshToken is null) - return null; - - var existingId = db.Datoms(JWTToken.AccessToken).FirstOrDefault().E; - if (existingId == EntityId.From(0)) - existingId = tx.TempId(); - - tx.Add(existingId, JWTToken.AccessToken, reply.AccessToken); - tx.Add(existingId, JWTToken.RefreshToken, reply.RefreshToken); - tx.Add(existingId, JWTToken.ExpiresAt, DateTimeOffset.FromUnixTimeSeconds(reply.CreatedAt).DateTime + TimeSpan.FromSeconds(reply.ExpiresIn)); + if (reply.AccessToken is null || reply.RefreshToken is null) return Optional.None; + + var existingId = GetEntityId(db); + var entityId = existingId.HasValue ? existingId.Value : tx.TempId(); + + tx.Add(entityId, AccessToken, reply.AccessToken); + tx.Add(entityId, RefreshToken, reply.RefreshToken); + tx.Add(entityId, ExpiresAt, DateTimeOffset.FromUnixTimeSeconds(reply.CreatedAt).DateTime + TimeSpan.FromSeconds(reply.ExpiresIn)); - return existingId; + return entityId; } /// /// Model for the JWT Token /// - /// public partial struct ReadOnly { /// diff --git a/src/Networking/NexusMods.Networking.NexusWebApi/Auth/OAuth2MessageFactory.cs b/src/Networking/NexusMods.Networking.NexusWebApi/Auth/OAuth2MessageFactory.cs index 607ebd4e1a..d3d80eda65 100644 --- a/src/Networking/NexusMods.Networking.NexusWebApi/Auth/OAuth2MessageFactory.cs +++ b/src/Networking/NexusMods.Networking.NexusWebApi/Auth/OAuth2MessageFactory.cs @@ -1,14 +1,8 @@ -using System.Reactive.Linq; -using DynamicData.Binding; using Microsoft.Extensions.Logging; -using NexusMods.Abstractions.MnemonicDB.Attributes; using NexusMods.Abstractions.NexusWebApi; using NexusMods.Abstractions.NexusWebApi.DTOs.OAuth; using NexusMods.Abstractions.NexusWebApi.Types; -using NexusMods.Abstractions.Serialization; -using NexusMods.Extensions.BCL; using NexusMods.MnemonicDB.Abstractions; -using NexusMods.MnemonicDB.Abstractions.Query; namespace NexusMods.Networking.NexusWebApi.Auth; @@ -31,31 +25,23 @@ public OAuth2MessageFactory( _conn = conn; _auth = auth; _logger = logger; - - _conn.ObserveDatoms(SliceDescriptor.Create(JWTToken.AccessToken, _conn.Registry)) - .Subscribe(_ => _cachedTokenEntity = null); } - private JWTToken.ReadOnly? _cachedTokenEntity; private readonly IConnection _conn; private async ValueTask GetOrRefreshToken(CancellationToken cancellationToken) { - if (!JWTToken.TryFind(_conn.Db, out var token)) - return null; - - _cachedTokenEntity = token; - if (!token.HasExpired) - return _cachedTokenEntity!.Value.AccessToken; + if (!JWTToken.TryFind(_conn.Db, out var token)) return null; + if (!token.HasExpired) return token.AccessToken; _logger.LogDebug("Refreshing expired OAuth token"); var newToken = await _auth.RefreshToken(token.RefreshToken, cancellationToken); var db = _conn.Db; using var tx = _conn.BeginTransaction(); - + var newTokenEntity = JWTToken.Create(db, tx, newToken!); - if (newTokenEntity is null) + if (!newTokenEntity.HasValue) { _logger.LogError("Invalid new token in OAuth2MessageFactory"); return null; @@ -63,8 +49,8 @@ public OAuth2MessageFactory( var result = await tx.Commit(); - _cachedTokenEntity = JWTToken.Load(result.Db, result[newTokenEntity.Value]); - return _cachedTokenEntity!.Value.AccessToken; + token = JWTToken.Load(result.Db, result[newTokenEntity.Value]); + return token.AccessToken; } /// diff --git a/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs b/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs index 1a46b94814..2f5c3ad886 100644 --- a/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs +++ b/src/Networking/NexusMods.Networking.NexusWebApi/LoginManager.cs @@ -135,7 +135,7 @@ public async Task LoginAsync(CancellationToken token = default) using var tx = _conn.BeginTransaction(); var newTokenEntity = JWTToken.Create(_conn.Db, tx, jwtToken); - if (newTokenEntity is null) + if (!newTokenEntity.HasValue) { _logger.LogError("Invalid new token data"); return;