From e379faaa07aeb3db455374242b36d07d99f8e078 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Mon, 5 Oct 2026 22:30:29 +0330 Subject: [PATCH] last ... --- Helpers/XApiKeyHelper.cs | 4 + Interfaces/IXApplicationProvider.cs | 4 +- .../XApplicationProvider+ApiKey.cs | 23 +- .../XApplicationProvider+ApiKeyUsage.cs | 9 +- .../XApplicationProvider+Application.cs | 14 +- .../XApplicationProvider+Custom.cs | 208 +++++++++++++++++- 6 files changed, 214 insertions(+), 48 deletions(-) diff --git a/Helpers/XApiKeyHelper.cs b/Helpers/XApiKeyHelper.cs index 09d5bb7..273bb22 100644 --- a/Helpers/XApiKeyHelper.cs +++ b/Helpers/XApiKeyHelper.cs @@ -1,3 +1,7 @@ +using System; +using System.Text; +using System.Security.Cryptography; + namespace xIds.Helpers { /// diff --git a/Interfaces/IXApplicationProvider.cs b/Interfaces/IXApplicationProvider.cs index f176185..7feb598 100644 --- a/Interfaces/IXApplicationProvider.cs +++ b/Interfaces/IXApplicationProvider.cs @@ -180,7 +180,7 @@ namespace xIds.Interfaces /// /// Task AddApiKeyAsync( - XApiKey item, + XApiKeyDto item, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ); @@ -537,7 +537,7 @@ namespace xIds.Interfaces /// /// Task> GetApplicationApiKeys( - Guid applicationId, + int applicationId, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ); diff --git a/Providers/XApplicationProvider/XApplicationProvider+ApiKey.cs b/Providers/XApplicationProvider/XApplicationProvider+ApiKey.cs index 2df3d7b..65f9b1d 100644 --- a/Providers/XApplicationProvider/XApplicationProvider+ApiKey.cs +++ b/Providers/XApplicationProvider/XApplicationProvider+ApiKey.cs @@ -30,7 +30,7 @@ namespace xIds.Providers /// /// public async Task AddApiKeyAsync( - XApiKey item, + XApiKeyDto item, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) @@ -86,12 +86,6 @@ namespace xIds.Providers // var entity = item.MapConvert(); - if (entity.Id.IsValidIntId()) - { - entity.Id = -1; - } - - // var entry = await dbContext.ApiKeys.AddAsync( entity: entity, cancellationToken: cancellationToken @@ -175,19 +169,8 @@ namespace xIds.Providers // Update Data on Exists Entity ... exists = exists.UpdateData( updateWith: item, - propertyWhiteList: [ - nameof(XApiKey.KeyHash), - nameof(XApiKey.KeyPrefix), - nameof(XApiKey.ExpiresAt), - nameof(XApiKey.CreatedOn), - nameof(XApiKey.RevokedAt), - nameof(XApiKey.RevokedBy), - nameof(XApiKey.LastUsedAt), - nameof(XApiKey.AllowedIPs), - nameof(XApiKey.ApplicationId), - nameof(XApiKey.AllowedScopes), - nameof(XApiKey.RateLimitPerMinute), - ] + propertyWhiteList: [], + propertyBlackList: [] ); // diff --git a/Providers/XApplicationProvider/XApplicationProvider+ApiKeyUsage.cs b/Providers/XApplicationProvider/XApplicationProvider+ApiKeyUsage.cs index b51cc9a..4af4c7c 100644 --- a/Providers/XApplicationProvider/XApplicationProvider+ApiKeyUsage.cs +++ b/Providers/XApplicationProvider/XApplicationProvider+ApiKeyUsage.cs @@ -121,13 +121,8 @@ namespace xIds.Providers // Update Data on Exists Entity ... exists = exists.UpdateData( updateWith: item, - propertyWhiteList: [ - nameof(XApiKeyUsage.ApiKeyId), - nameof(XApiKeyUsage.Endpoint), - nameof(XApiKeyUsage.ClientIP), - nameof(XApiKeyUsage.HttpMethod), - nameof(XApiKeyUsage.StatusCode), - nameof(XApiKeyUsage.RequestedOn), + propertyWhiteList: [], + propertyBlackList: [ nameof(XApiKeyUsage.ResponseTimeMs), ] ); diff --git a/Providers/XApplicationProvider/XApplicationProvider+Application.cs b/Providers/XApplicationProvider/XApplicationProvider+Application.cs index a402919..64456a5 100644 --- a/Providers/XApplicationProvider/XApplicationProvider+Application.cs +++ b/Providers/XApplicationProvider/XApplicationProvider+Application.cs @@ -129,18 +129,16 @@ namespace xIds.Providers XException.NotAllowed.Throw(); } + // + item.UpdatedAt = DateTime.UtcNow; + // // Update Data on Exists Entity ... exists = exists.UpdateData( updateWith: item, - propertyWhiteList: [ - nameof(XApplication.Name), - nameof(XApplication.Type), - nameof(XApplication.OwnerId), - nameof(XApplication.IsActive), - nameof(XApplication.CreatedOn), - nameof(XApplication.UpdatedAt), - nameof(XApplication.Description), + propertyWhiteList: [], + propertyBlackList: [ + nameof(XApplication.ApiKeys), ] ); diff --git a/Providers/XApplicationProvider/XApplicationProvider+Custom.cs b/Providers/XApplicationProvider/XApplicationProvider+Custom.cs index 7725ea0..70e646b 100644 --- a/Providers/XApplicationProvider/XApplicationProvider+Custom.cs +++ b/Providers/XApplicationProvider/XApplicationProvider+Custom.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using xIds.Helpers; using System.Threading; using xCommons.Extensions; using xIdentityModels.Dtos; @@ -7,6 +8,7 @@ using xExceptions.Constants; using System.Threading.Tasks; using xIdentityModels.Models; using System.Collections.Generic; +using System.Security.Cryptography; namespace xIds.Providers { @@ -80,15 +82,43 @@ namespace xIds.Providers { expiration = TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes); } - - // - var // - var item = new XApiKeyDto + // Generate New Key ... + (string plainKey, string keyHash, string prefix) = XApiKeyHelper.Generate(); + var expireAt = DateTime.UtcNow.Add(expiration.Value); + + // + var _allowedScopes = scopes.ToJSON(); + var _allowedIPs = allowedIPs.ToListString(); + + // + // Instance Dto Item ... + var result = new XApiKeyDto { - - } + RevokedAt = null, + KeyHash = keyHash, + LastUsedAt = null, + KeyPrefix = prefix, + ExpiresAt = expireAt, + RevokedBy = string.Empty, + AllowedIPs = _allowedIPs, + CreatedOn = DateTime.UtcNow, + ApplicationId = applicationId, + AllowedScopes = _allowedScopes, + RateLimitPerMinute = rateLimit.Value + }; + + // + // Add Item to Database ... + result = await AddApiKeyAsync( + item: item, + userInfo: userInfo, + cancellationToken: cancellationToken + ); + + // + return result; } /// @@ -103,7 +133,65 @@ namespace xIds.Providers XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) - { } + { + // + // Validate ... + if ( + apiKeyId.IsDefaultGuid() || + userInfo.IsNullOrDefault()) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve ApiKey ... + var item = await GetApiKeyAsync( + id: apiKeyId, + userInfo: userInfo, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (item.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Permission Checking ... + var application = await GetApplicationAsync( + userInfo: userInfo, + includeBuilder: null, + id: item.ApplicationId, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (application.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + if (!IsOwned(application, userInfo)) + { + XException.NotAllowed.Throw(); + } + + // + // Update Revoke Info ... + item.RevokedAt = DateTime.UtcNow; + item.RevokedBy = userInfo.UserId; + + // + item = await UpdateApiKeyAsync( + id: item.Id, + item: item, + userInfo: userInfo, + cancellationToken: cancellationToken + ); + + // + var result = !item.IsNullOrDefault(); + return result; + } /// /// Renew Specified Api Key ... @@ -119,7 +207,61 @@ namespace xIds.Providers XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) - { } + { + // + // Validate ... + if ( + apiKeyId.IsDefaultGuid() || + userInfo.IsNullOrDefault() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Item ... + var result = await GetApiKeyAsync( + id: apiKeyId, + userInfo: userInfo, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Expired Date ... + DateTime? expiredDate = null; + if (!newExpiration.HasValue) + { + // + newExpiration = TimeSpan + .FromMinutes(apiKeyConfiguration.DefaultExpirationMinutes); + expiredDate = DateTime.UtcNow.Add(newExpiration.Value); + } + if (!expiredDate.HasValue) + { + XException.InvalidArgs.Throw(); + } + + // + // Update Item ... + result.ExpiresAt = expiredDate.Value; + + // + result = await UpdateApiKeyAsync( + item: result, + id: result.Id, + userInfo: userInfo, + cancellationToken: cancellationToken + ); + + // + return result; + } /// /// Retrieve All Api Keys for Specified Application ... @@ -129,11 +271,52 @@ namespace xIds.Providers /// /// public async Task> GetApplicationApiKeys( - Guid applicationId, + int applicationId, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) - { } + { + // + // Validate ... + if ( + userInfo.IsNullOrDefault() || + !applicationId.IsValidIntId() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Permission Checking ... + var application = await GetApplicationAsync( + userInfo: userInfo, + includeBuilder: null, + id: applicationId, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + if (application.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + if (!IsOwned(application, userInfo)) + { + XException.NotAllowed.Throw(); + } + + // + var result = await FindManyApiKeyAsync( + userInfo: userInfo, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.Id), + predicate: x => x.ApplicationId == applicationId + ); + + // + return result; + } /// /// Validate Specified Api Key in based on ClientIP ... @@ -149,7 +332,10 @@ namespace xIds.Providers XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) - { } + { + // + + } #endregion } } \ No newline at end of file