using System; using System.Linq; using xIds.Helpers; using System.Threading; using xCommons.Extensions; using xIdentityModels.Dtos; using xExceptions.Constants; using System.Threading.Tasks; using xIdentityModels.Models; using System.Collections.Generic; using System.Security.Cryptography; namespace xIds.Providers { public partial class XApplicationProvider { // #region Custom Actions ... /// /// Generate a New ApiKey and Add It to DB ... /// /// /// /// /// /// /// /// /// public async Task CreateApiKey( int applicationId, TimeSpan? expiration = null, IEnumerable scopes = null, IEnumerable allowedIPs = null, int? rateLimit = null, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) { // // Validate ... if ( userInfo.IsNullOrDefault() || !applicationId.IsValidIntId() ) { XException.InvalidArgs.Throw(); } // // Check Application Exists ... var application = await GetApplicationAsync( id: applicationId, userInfo: userInfo, includeBuilder: null, ignoreSoftDeleteds: true, cancellationToken: cancellationToken ); if (application.IsNullOrDefault()) { XException.NotFound.Throw(); } // // Validate Owner ... if (!IsOwned(application, userInfo)) { XException.NotAllowed.Throw(); } // // Normalizing ... if (!rateLimit.HasValue) { rateLimit = apiKeyConfiguration.DefaultRateLimit; } if (!expiration.HasValue) { expiration = TimeSpan.FromMinutes(apiKeyConfiguration.DefaultExpirationMinutes); } else if (expiration.Value > TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes)) { expiration = TimeSpan.FromMinutes(apiKeyConfiguration.MaxExpirationMinutes); } // // 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; } /// /// Revoke Specified Api Key ... /// /// /// /// /// public async Task RevokeApiKey( Guid apiKeyId, 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 ... /// /// /// /// /// /// public async Task RotateApiKey( Guid apiKeyId, TimeSpan? newExpiration = null, 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 ... /// /// /// /// /// public async Task> GetApplicationApiKeys( 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 ... /// /// /// /// /// /// public async Task ValidateApiKey( string apiKey, string clientIP, XUserClaimsInfoDto userInfo = null, CancellationToken cancellationToken = default ) { // } #endregion } }