diff --git a/DysonNetwork.Pass/Account/BotAccountReceiverGrpc.cs b/DysonNetwork.Pass/Account/BotAccountReceiverGrpc.cs index 215bec6..dd0c627 100644 --- a/DysonNetwork.Pass/Account/BotAccountReceiverGrpc.cs +++ b/DysonNetwork.Pass/Account/BotAccountReceiverGrpc.cs @@ -169,7 +169,9 @@ public class BotAccountReceiverGrpc( var accountId = Guid.Parse(request.AccountId); var key = await db.ApiKeys - .FirstOrDefaultAsync(k => k.Id == keyId && k.AccountId == accountId); + .Include(k => k.Session) + .Where(k => k.Id == keyId && k.AccountId == accountId) + .FirstOrDefaultAsync(); if (key == null) throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found")); @@ -187,7 +189,7 @@ public class BotAccountReceiverGrpc( { var keyId = Guid.Parse(request.Id); var key = await db.ApiKeys - .Include(k => k.Account) + .Include(k => k.Session) .FirstOrDefaultAsync(k => k.Id == keyId); if (key == null) @@ -203,7 +205,7 @@ public class BotAccountReceiverGrpc( { var keyId = Guid.Parse(request.Id); var key = await db.ApiKeys - .Include(k => k.Account) + .Include(k => k.Session) .FirstOrDefaultAsync(k => k.Id == keyId); if (key == null) diff --git a/DysonNetwork.Pass/Auth/ApiKey.cs b/DysonNetwork.Pass/Auth/ApiKey.cs index 05c5519..4a1781a 100644 --- a/DysonNetwork.Pass/Auth/ApiKey.cs +++ b/DysonNetwork.Pass/Auth/ApiKey.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json.Serialization; using DysonNetwork.Shared.Data; +using NodaTime.Serialization.Protobuf; namespace DysonNetwork.Pass.Auth; @@ -27,7 +28,9 @@ public class ApiKey : ModelBase Label = Label, AccountId = AccountId.ToString(), SessionId = SessionId.ToString(), - Key = Key + Key = Key, + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; } @@ -39,7 +42,9 @@ public class ApiKey : ModelBase AccountId = Guid.Parse(proto.AccountId), SessionId = Guid.Parse(proto.SessionId), Label = proto.Label, - Key = proto.Key + Key = proto.Key, + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant() }; } } \ No newline at end of file diff --git a/DysonNetwork.Pass/Auth/AuthService.cs b/DysonNetwork.Pass/Auth/AuthService.cs index f9669fb..bf14188 100644 --- a/DysonNetwork.Pass/Auth/AuthService.cs +++ b/DysonNetwork.Pass/Auth/AuthService.cs @@ -317,7 +317,7 @@ public class AuthService( return factor.VerifyPassword(pinCode); } - + public async Task GetApiKey(Guid id, Guid? accountId = null) { var key = await db.ApiKeys @@ -340,13 +340,13 @@ public class AuthService( ExpiredAt = expiredAt }, }; - + db.ApiKeys.Add(key); await db.SaveChangesAsync(); - + return key; } - + public async Task IssueApiKeyToken(ApiKey key) { key.Session.LastGrantedAt = SystemClock.Instance.GetCurrentInstant(); @@ -355,26 +355,48 @@ public class AuthService( var tk = CreateToken(key.Session); return tk; } - + public async Task RevokeApiKeyToken(ApiKey key) { db.Remove(key); db.Remove(key.Session); await db.SaveChangesAsync(); } - + public async Task RotateApiKeyToken(ApiKey key) { - var originalSession = key.Session; - db.Remove(originalSession); - key.Session = new AuthSession + await using var transaction = await db.Database.BeginTransactionAsync(); + try { - AccountId = key.AccountId, - ExpiredAt = originalSession.ExpiredAt - }; - db.Add(key.Session); - await db.SaveChangesAsync(); - return key; + var oldSessionId = key.SessionId; + + // Create new session + var newSession = new AuthSession + { + AccountId = key.AccountId, + ExpiredAt = key.Session?.ExpiredAt + }; + + db.AuthSessions.Add(newSession); + await db.SaveChangesAsync(); + + // Update ApiKey to point to new session + key.SessionId = newSession.Id; + key.Session = newSession; + db.ApiKeys.Update(key); + await db.SaveChangesAsync(); + + // Delete old session + await db.AuthSessions.Where(s => s.Id == oldSessionId).ExecuteDeleteAsync(); + + await transaction.CommitAsync(); + return key; + } + catch + { + await transaction.RollbackAsync(); + throw; + } } // Helper methods for Base64Url encoding/decoding diff --git a/DysonNetwork.Shared/Data/Account.cs b/DysonNetwork.Shared/Data/Account.cs index 7807555..46f2031 100644 --- a/DysonNetwork.Shared/Data/Account.cs +++ b/DysonNetwork.Shared/Data/Account.cs @@ -328,7 +328,9 @@ public class ApiKeyReference : ModelBase Label = Label, AccountId = AccountId.ToString(), SessionId = SessionId.ToString(), - Key = Key + Key = Key, + CreatedAt = CreatedAt.ToTimestamp(), + UpdatedAt = UpdatedAt.ToTimestamp() }; } @@ -340,7 +342,9 @@ public class ApiKeyReference : ModelBase AccountId = Guid.Parse(proto.AccountId), SessionId = Guid.Parse(proto.SessionId), Label = proto.Label, - Key = proto.Key + Key = proto.Key, + CreatedAt = proto.CreatedAt.ToInstant(), + UpdatedAt = proto.UpdatedAt.ToInstant() }; } } \ No newline at end of file diff --git a/DysonNetwork.Shared/Proto/develop.proto b/DysonNetwork.Shared/Proto/develop.proto index 180c251..11e5e40 100644 --- a/DysonNetwork.Shared/Proto/develop.proto +++ b/DysonNetwork.Shared/Proto/develop.proto @@ -143,6 +143,8 @@ message ApiKey { string account_id = 3; string session_id = 4; google.protobuf.StringValue key = 5; + google.protobuf.Timestamp created_at = 6; + google.protobuf.Timestamp updated_at = 7; } message GetApiKeyRequest { @@ -166,7 +168,7 @@ service BotAccountReceiverService { rpc CreateBotAccount(CreateBotAccountRequest) returns (CreateBotAccountResponse); rpc UpdateBotAccount(UpdateBotAccountRequest) returns (UpdateBotAccountResponse); rpc DeleteBotAccount(DeleteBotAccountRequest) returns (DeleteBotAccountResponse); - + rpc GetApiKey(GetApiKeyRequest) returns (ApiKey); rpc ListApiKey(ListApiKeyRequest) returns (GetApiKeyBatchResponse); rpc CreateApiKey(ApiKey) returns (ApiKey);