🐛 Fix rotate key
This commit is contained in:
@@ -169,7 +169,9 @@ public class BotAccountReceiverGrpc(
|
|||||||
var accountId = Guid.Parse(request.AccountId);
|
var accountId = Guid.Parse(request.AccountId);
|
||||||
|
|
||||||
var key = await db.ApiKeys
|
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)
|
if (key == null)
|
||||||
throw new RpcException(new Grpc.Core.Status(StatusCode.NotFound, "API key not found"));
|
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 keyId = Guid.Parse(request.Id);
|
||||||
var key = await db.ApiKeys
|
var key = await db.ApiKeys
|
||||||
.Include(k => k.Account)
|
.Include(k => k.Session)
|
||||||
.FirstOrDefaultAsync(k => k.Id == keyId);
|
.FirstOrDefaultAsync(k => k.Id == keyId);
|
||||||
|
|
||||||
if (key == null)
|
if (key == null)
|
||||||
@@ -203,7 +205,7 @@ public class BotAccountReceiverGrpc(
|
|||||||
{
|
{
|
||||||
var keyId = Guid.Parse(request.Id);
|
var keyId = Guid.Parse(request.Id);
|
||||||
var key = await db.ApiKeys
|
var key = await db.ApiKeys
|
||||||
.Include(k => k.Account)
|
.Include(k => k.Session)
|
||||||
.FirstOrDefaultAsync(k => k.Id == keyId);
|
.FirstOrDefaultAsync(k => k.Id == keyId);
|
||||||
|
|
||||||
if (key == null)
|
if (key == null)
|
||||||
|
@@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
|
using NodaTime.Serialization.Protobuf;
|
||||||
|
|
||||||
namespace DysonNetwork.Pass.Auth;
|
namespace DysonNetwork.Pass.Auth;
|
||||||
|
|
||||||
@@ -27,7 +28,9 @@ public class ApiKey : ModelBase
|
|||||||
Label = Label,
|
Label = Label,
|
||||||
AccountId = AccountId.ToString(),
|
AccountId = AccountId.ToString(),
|
||||||
SessionId = SessionId.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),
|
AccountId = Guid.Parse(proto.AccountId),
|
||||||
SessionId = Guid.Parse(proto.SessionId),
|
SessionId = Guid.Parse(proto.SessionId),
|
||||||
Label = proto.Label,
|
Label = proto.Label,
|
||||||
Key = proto.Key
|
Key = proto.Key,
|
||||||
|
CreatedAt = proto.CreatedAt.ToInstant(),
|
||||||
|
UpdatedAt = proto.UpdatedAt.ToInstant()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -317,7 +317,7 @@ public class AuthService(
|
|||||||
|
|
||||||
return factor.VerifyPassword(pinCode);
|
return factor.VerifyPassword(pinCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiKey?> GetApiKey(Guid id, Guid? accountId = null)
|
public async Task<ApiKey?> GetApiKey(Guid id, Guid? accountId = null)
|
||||||
{
|
{
|
||||||
var key = await db.ApiKeys
|
var key = await db.ApiKeys
|
||||||
@@ -340,13 +340,13 @@ public class AuthService(
|
|||||||
ExpiredAt = expiredAt
|
ExpiredAt = expiredAt
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
db.ApiKeys.Add(key);
|
db.ApiKeys.Add(key);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> IssueApiKeyToken(ApiKey key)
|
public async Task<string> IssueApiKeyToken(ApiKey key)
|
||||||
{
|
{
|
||||||
key.Session.LastGrantedAt = SystemClock.Instance.GetCurrentInstant();
|
key.Session.LastGrantedAt = SystemClock.Instance.GetCurrentInstant();
|
||||||
@@ -355,26 +355,48 @@ public class AuthService(
|
|||||||
var tk = CreateToken(key.Session);
|
var tk = CreateToken(key.Session);
|
||||||
return tk;
|
return tk;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RevokeApiKeyToken(ApiKey key)
|
public async Task RevokeApiKeyToken(ApiKey key)
|
||||||
{
|
{
|
||||||
db.Remove(key);
|
db.Remove(key);
|
||||||
db.Remove(key.Session);
|
db.Remove(key.Session);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ApiKey> RotateApiKeyToken(ApiKey key)
|
public async Task<ApiKey> RotateApiKeyToken(ApiKey key)
|
||||||
{
|
{
|
||||||
var originalSession = key.Session;
|
await using var transaction = await db.Database.BeginTransactionAsync();
|
||||||
db.Remove(originalSession);
|
try
|
||||||
key.Session = new AuthSession
|
|
||||||
{
|
{
|
||||||
AccountId = key.AccountId,
|
var oldSessionId = key.SessionId;
|
||||||
ExpiredAt = originalSession.ExpiredAt
|
|
||||||
};
|
// Create new session
|
||||||
db.Add(key.Session);
|
var newSession = new AuthSession
|
||||||
await db.SaveChangesAsync();
|
{
|
||||||
return key;
|
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
|
// Helper methods for Base64Url encoding/decoding
|
||||||
|
@@ -328,7 +328,9 @@ public class ApiKeyReference : ModelBase
|
|||||||
Label = Label,
|
Label = Label,
|
||||||
AccountId = AccountId.ToString(),
|
AccountId = AccountId.ToString(),
|
||||||
SessionId = SessionId.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),
|
AccountId = Guid.Parse(proto.AccountId),
|
||||||
SessionId = Guid.Parse(proto.SessionId),
|
SessionId = Guid.Parse(proto.SessionId),
|
||||||
Label = proto.Label,
|
Label = proto.Label,
|
||||||
Key = proto.Key
|
Key = proto.Key,
|
||||||
|
CreatedAt = proto.CreatedAt.ToInstant(),
|
||||||
|
UpdatedAt = proto.UpdatedAt.ToInstant()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -143,6 +143,8 @@ message ApiKey {
|
|||||||
string account_id = 3;
|
string account_id = 3;
|
||||||
string session_id = 4;
|
string session_id = 4;
|
||||||
google.protobuf.StringValue key = 5;
|
google.protobuf.StringValue key = 5;
|
||||||
|
google.protobuf.Timestamp created_at = 6;
|
||||||
|
google.protobuf.Timestamp updated_at = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetApiKeyRequest {
|
message GetApiKeyRequest {
|
||||||
@@ -166,7 +168,7 @@ service BotAccountReceiverService {
|
|||||||
rpc CreateBotAccount(CreateBotAccountRequest) returns (CreateBotAccountResponse);
|
rpc CreateBotAccount(CreateBotAccountRequest) returns (CreateBotAccountResponse);
|
||||||
rpc UpdateBotAccount(UpdateBotAccountRequest) returns (UpdateBotAccountResponse);
|
rpc UpdateBotAccount(UpdateBotAccountRequest) returns (UpdateBotAccountResponse);
|
||||||
rpc DeleteBotAccount(DeleteBotAccountRequest) returns (DeleteBotAccountResponse);
|
rpc DeleteBotAccount(DeleteBotAccountRequest) returns (DeleteBotAccountResponse);
|
||||||
|
|
||||||
rpc GetApiKey(GetApiKeyRequest) returns (ApiKey);
|
rpc GetApiKey(GetApiKeyRequest) returns (ApiKey);
|
||||||
rpc ListApiKey(ListApiKeyRequest) returns (GetApiKeyBatchResponse);
|
rpc ListApiKey(ListApiKeyRequest) returns (GetApiKeyBatchResponse);
|
||||||
rpc CreateApiKey(ApiKey) returns (ApiKey);
|
rpc CreateApiKey(ApiKey) returns (ApiKey);
|
||||||
|
Reference in New Issue
Block a user